test_pagure_flask_api_project.py 112 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015-2018 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. """
  7. __requires__ = ['SQLAlchemy >= 0.8']
  8. import pkg_resources
  9. import json
  10. import unittest
  11. import shutil
  12. import sys
  13. import tempfile
  14. import os
  15. import pygit2
  16. from celery.result import EagerResult
  17. from mock import patch, Mock
  18. sys.path.insert(0, os.path.join(os.path.dirname(
  19. os.path.abspath(__file__)), '..'))
  20. import pagure.flask_app
  21. import pagure.lib
  22. import tests
  23. from pagure.lib.repo import PagureRepo
  24. class PagureFlaskApiProjecttests(tests.Modeltests):
  25. """ Tests for the flask API of pagure for issue """
  26. def setUp(self):
  27. super(PagureFlaskApiProjecttests, self).setUp()
  28. self.gga_patcher = patch(
  29. 'pagure.lib.tasks.generate_gitolite_acls.delay')
  30. self.mock_gen_acls = self.gga_patcher.start()
  31. task_result = EagerResult('abc-1234', True, "SUCCESS")
  32. self.mock_gen_acls.return_value = task_result
  33. def tearDown(self):
  34. self.gga_patcher.stop()
  35. super(PagureFlaskApiProjecttests, self).tearDown()
  36. def test_api_git_tags(self):
  37. """ Test the api_git_tags method of the flask api. """
  38. tests.create_projects(self.session)
  39. # Create a git repo to play with
  40. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  41. repo = pygit2.init_repository(gitrepo, bare=True)
  42. newpath = tempfile.mkdtemp(prefix='pagure-fork-test')
  43. repopath = os.path.join(newpath, 'test')
  44. clone_repo = pygit2.clone_repository(gitrepo, repopath)
  45. # Create a file in that git repo
  46. with open(os.path.join(repopath, 'sources'), 'w') as stream:
  47. stream.write('foo\n bar')
  48. clone_repo.index.add('sources')
  49. clone_repo.index.write()
  50. # Commits the files added
  51. tree = clone_repo.index.write_tree()
  52. author = pygit2.Signature(
  53. 'Alice Author', 'alice@authors.tld')
  54. committer = pygit2.Signature(
  55. 'Cecil Committer', 'cecil@committers.tld')
  56. clone_repo.create_commit(
  57. 'refs/heads/master', # the name of the reference to update
  58. author,
  59. committer,
  60. 'Add sources file for testing',
  61. # binary string representing the tree object ID
  62. tree,
  63. # list of binary strings representing parents of the new commit
  64. []
  65. )
  66. refname = 'refs/heads/master:refs/heads/master'
  67. ori_remote = clone_repo.remotes[0]
  68. PagureRepo.push(ori_remote, refname)
  69. # Tag our first commit
  70. first_commit = repo.revparse_single('HEAD')
  71. tagger = pygit2.Signature('Alice Doe', 'adoe@example.com', 12347, 0)
  72. repo.create_tag(
  73. "0.0.1", first_commit.oid.hex, pygit2.GIT_OBJ_COMMIT, tagger,
  74. "Release 0.0.1")
  75. # Check tags
  76. output = self.app.get('/api/0/test/git/tags')
  77. self.assertEqual(output.status_code, 200)
  78. data = json.loads(output.data)
  79. self.assertDictEqual(
  80. data,
  81. {'tags': ['0.0.1'], 'total_tags': 1}
  82. )
  83. # Check tags with commits
  84. output = self.app.get('/api/0/test/git/tags?with_commits=True')
  85. self.assertEqual(output.status_code, 200)
  86. data = json.loads(output.data)
  87. data['tags']['0.0.1'] = 'bb8fa2aa199da08d6085e1c9badc3d83d188d38c'
  88. self.assertDictEqual(
  89. data,
  90. {
  91. u'tags': {u'0.0.1': u'bb8fa2aa199da08d6085e1c9badc3d83d188d38c'},
  92. u'total_tags': 1}
  93. )
  94. shutil.rmtree(newpath)
  95. def test_api_git_branches(self):
  96. """ Test the api_git_branches method of the flask api. """
  97. # Create a git repo to add branches to
  98. tests.create_projects(self.session)
  99. repo_path = os.path.join(self.path, 'repos', 'test.git')
  100. tests.add_content_git_repo(repo_path)
  101. new_repo_path = tempfile.mkdtemp(prefix='pagure-api-git-branches-test')
  102. clone_repo = pygit2.clone_repository(repo_path, new_repo_path)
  103. # Create two other branches based on master
  104. for branch in ['pats-win-49', 'pats-win-51']:
  105. clone_repo.create_branch(branch, clone_repo.head.get_object())
  106. refname = 'refs/heads/{0}:refs/heads/{0}'.format(branch)
  107. PagureRepo.push(clone_repo.remotes[0], refname)
  108. # Check that the branches show up on the API
  109. output = self.app.get('/api/0/test/git/branches')
  110. # Delete the cloned git repo after the API call
  111. shutil.rmtree(new_repo_path)
  112. # Verify the API data
  113. self.assertEqual(output.status_code, 200)
  114. data = json.loads(output.data)
  115. self.assertDictEqual(
  116. data,
  117. {
  118. 'branches': ['master', 'pats-win-49', 'pats-win-51'],
  119. 'total_branches': 3
  120. }
  121. )
  122. def test_api_git_branches_empty_repo(self):
  123. """ Test the api_git_branches method of the flask api when the repo is
  124. empty.
  125. """
  126. # Create a git repo without any branches
  127. tests.create_projects(self.session)
  128. repo_base_path = os.path.join(self.path, 'repos')
  129. tests.create_projects_git(repo_base_path)
  130. # Check that no branches show up on the API
  131. output = self.app.get('/api/0/test/git/branches')
  132. self.assertEqual(output.status_code, 200)
  133. data = json.loads(output.data)
  134. self.assertDictEqual(
  135. data,
  136. {
  137. 'branches': [],
  138. 'total_branches': 0
  139. }
  140. )
  141. def test_api_git_branches_no_repo(self):
  142. """ Test the api_git_branches method of the flask api when there is no
  143. repo on a project.
  144. """
  145. tests.create_projects(self.session)
  146. output = self.app.get('/api/0/test/git/branches')
  147. self.assertEqual(output.status_code, 404)
  148. def test_api_git_urls(self):
  149. """ Test the api_project_git_urls method of the flask api.
  150. """
  151. tests.create_projects(self.session)
  152. output = self.app.get('/api/0/test/git/urls')
  153. self.assertEqual(output.status_code, 200)
  154. expected_rv = {
  155. 'urls': {
  156. 'git': 'git://pagure.org/test.git',
  157. 'ssh': 'ssh://git@pagure.org/test.git'
  158. },
  159. 'total_urls': 2
  160. }
  161. data = json.loads(output.data)
  162. self.assertDictEqual(data, expected_rv)
  163. def test_api_git_urls_no_project(self):
  164. """ Test the api_project_git_urls method of the flask api when there is
  165. no project.
  166. """
  167. output = self.app.get('/api/0/test1234/git/urls')
  168. self.assertEqual(output.status_code, 404)
  169. expected_rv = {
  170. 'error': 'Project not found',
  171. 'error_code': 'ENOPROJECT'
  172. }
  173. data = json.loads(output.data)
  174. self.assertDictEqual(data, expected_rv)
  175. @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
  176. def test_api_git_urls_private_project(self):
  177. """ Test the api_project_git_urls method of the flask api when the
  178. project is private.
  179. """
  180. tests.create_projects(self.session)
  181. tests.create_tokens(self.session)
  182. tests.create_tokens_acl(self.session, 'aaabbbcccddd')
  183. headers = {'Authorization': 'token aaabbbcccddd'}
  184. test_project = pagure.lib._get_project(self.session, 'test')
  185. test_project.private = True
  186. self.session.add(test_project)
  187. self.session.commit()
  188. output = self.app.get('/api/0/test/git/urls', headers=headers)
  189. self.assertEqual(output.status_code, 200)
  190. expected_rv = {
  191. 'urls': {
  192. 'git': 'git://pagure.org/test.git',
  193. 'ssh': 'ssh://git@pagure.org/test.git'
  194. },
  195. 'total_urls': 2
  196. }
  197. data = json.loads(output.data)
  198. self.assertDictEqual(data, expected_rv)
  199. @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
  200. def test_api_git_urls_private_project_no_login(self):
  201. """ Test the api_project_git_urls method of the flask api when the
  202. project is private and the user is not logged in.
  203. """
  204. tests.create_projects(self.session)
  205. test_project = pagure.lib._get_project(self.session, 'test')
  206. test_project.private = True
  207. self.session.add(test_project)
  208. self.session.commit()
  209. output = self.app.get('/api/0/test/git/urls')
  210. self.assertEqual(output.status_code, 404)
  211. expected_rv = {
  212. 'error': 'Project not found',
  213. 'error_code': 'ENOPROJECT'
  214. }
  215. data = json.loads(output.data)
  216. self.assertDictEqual(data, expected_rv)
  217. def test_api_projects_pattern(self):
  218. """ Test the api_projects method of the flask api. """
  219. tests.create_projects(self.session)
  220. output = self.app.get('/api/0/projects?pattern=test')
  221. self.assertEqual(output.status_code, 200)
  222. data = json.loads(output.data)
  223. data['projects'][0]['date_created'] = "1436527638"
  224. data['projects'][0]['date_modified'] = "1436527638"
  225. expected_data = {
  226. "args": {
  227. "fork": None,
  228. "namespace": None,
  229. "owner": None,
  230. "pattern": "test",
  231. "short": False,
  232. "tags": [],
  233. "username": None
  234. },
  235. "projects": [
  236. {
  237. "access_groups": {
  238. "admin": [],
  239. "commit": [],
  240. "ticket": []
  241. },
  242. "access_users": {
  243. "admin": [],
  244. "commit": [],
  245. "owner": [
  246. "pingou"
  247. ],
  248. "ticket": []
  249. },
  250. "close_status": [
  251. "Invalid",
  252. "Insufficient data",
  253. "Fixed",
  254. "Duplicate"
  255. ],
  256. "custom_keys": [],
  257. "date_created": "1436527638",
  258. "date_modified": "1436527638",
  259. "description": "test project #1",
  260. "fullname": "test",
  261. "url_path": "test",
  262. "id": 1,
  263. "milestones": {},
  264. "name": "test",
  265. "namespace": None,
  266. "parent": None,
  267. "priorities": {},
  268. "tags": [],
  269. "user": {
  270. "fullname": "PY C",
  271. "name": "pingou"
  272. }
  273. }
  274. ],
  275. "total_projects": 1
  276. }
  277. self.assertDictEqual(data, expected_data)
  278. def test_api_projects_pattern_short(self):
  279. """ Test the api_projects method of the flask api. """
  280. tests.create_projects(self.session)
  281. output = self.app.get('/api/0/projects?pattern=te*&short=1')
  282. self.assertEqual(output.status_code, 200)
  283. data = json.loads(output.data)
  284. expected_data = {
  285. "args": {
  286. "fork": None,
  287. "namespace": None,
  288. "owner": None,
  289. "pattern": "te*",
  290. "short": True,
  291. "tags": [],
  292. "username": None
  293. },
  294. "projects": [
  295. {
  296. "description": "test project #1",
  297. "fullname": "test",
  298. "name": "test",
  299. "namespace": None
  300. },
  301. {
  302. "description": "test project #2",
  303. "fullname": "test2",
  304. "name": "test2",
  305. "namespace": None
  306. },
  307. {
  308. "description": "namespaced test project",
  309. "fullname": "somenamespace/test3",
  310. "name": "test3",
  311. "namespace": "somenamespace"
  312. }
  313. ],
  314. "total_projects": 3
  315. }
  316. self.assertDictEqual(data, expected_data)
  317. def test_api_projects(self):
  318. """ Test the api_projects method of the flask api. """
  319. tests.create_projects(self.session)
  320. # Check before adding
  321. repo = pagure.lib.get_authorized_project(self.session, 'test')
  322. self.assertEqual(repo.tags, [])
  323. # Adding a tag
  324. output = pagure.lib.update_tags(
  325. self.session, repo, 'infra', 'pingou',
  326. None)
  327. self.assertEqual(output, ['Project tagged with: infra'])
  328. # Check after adding
  329. repo = pagure.lib.get_authorized_project(self.session, 'test')
  330. self.assertEqual(len(repo.tags), 1)
  331. self.assertEqual(repo.tags_text, ['infra'])
  332. # Check the API
  333. output = self.app.get('/api/0/projects?tags=inf')
  334. self.assertEqual(output.status_code, 200)
  335. data = json.loads(output.data)
  336. self.assertDictEqual(
  337. data,
  338. {
  339. "total_projects": 0,
  340. "projects": [],
  341. "args": {
  342. "fork": None,
  343. "namespace": None,
  344. "owner": None,
  345. "pattern": None,
  346. "short": False,
  347. "tags": ["inf"],
  348. "username": None
  349. }
  350. }
  351. )
  352. output = self.app.get('/api/0/projects?tags=infra')
  353. self.assertEqual(output.status_code, 200)
  354. data = json.loads(output.data)
  355. data['projects'][0]['date_created'] = "1436527638"
  356. data['projects'][0]['date_modified'] = "1436527638"
  357. expected_data = {
  358. "args": {
  359. "fork": None,
  360. "namespace": None,
  361. "owner": None,
  362. "pattern": None,
  363. "short": False,
  364. "tags": ["infra"],
  365. "username": None
  366. },
  367. "projects": [{
  368. "access_groups": {
  369. "admin": [],
  370. "commit": [],
  371. "ticket": []},
  372. "access_users": {
  373. "admin": [],
  374. "commit": [],
  375. "owner": ["pingou"],
  376. "ticket": []},
  377. "close_status": [
  378. "Invalid",
  379. "Insufficient data",
  380. "Fixed",
  381. "Duplicate"
  382. ],
  383. "custom_keys": [],
  384. "date_created": "1436527638",
  385. "date_modified": "1436527638",
  386. "description": "test project #1",
  387. "fullname": "test",
  388. "url_path": "test",
  389. "id": 1,
  390. "milestones": {},
  391. "name": "test",
  392. "namespace": None,
  393. "parent": None,
  394. "priorities": {},
  395. "tags": ["infra"],
  396. "user": {
  397. "fullname": "PY C",
  398. "name": "pingou"
  399. }
  400. }],
  401. "total_projects": 1
  402. }
  403. self.assertDictEqual(data, expected_data)
  404. output = self.app.get('/api/0/projects?owner=pingou')
  405. self.assertEqual(output.status_code, 200)
  406. data = json.loads(output.data)
  407. data['projects'][0]['date_created'] = "1436527638"
  408. data['projects'][0]['date_modified'] = "1436527638"
  409. data['projects'][1]['date_created'] = "1436527638"
  410. data['projects'][1]['date_modified'] = "1436527638"
  411. data['projects'][2]['date_created'] = "1436527638"
  412. data['projects'][2]['date_modified'] = "1436527638"
  413. expected_data = {
  414. "args": {
  415. "fork": None,
  416. "namespace": None,
  417. "owner": "pingou",
  418. "pattern": None,
  419. "short": False,
  420. "tags": [],
  421. "username": None
  422. },
  423. "projects": [
  424. {
  425. "access_groups": {
  426. "admin": [],
  427. "commit": [],
  428. "ticket": []
  429. },
  430. "access_users": {
  431. "admin": [],
  432. "commit": [],
  433. "owner": ["pingou"],
  434. "ticket": []
  435. },
  436. "close_status": [
  437. "Invalid",
  438. "Insufficient data",
  439. "Fixed",
  440. "Duplicate"
  441. ],
  442. "custom_keys": [],
  443. "date_created": "1436527638",
  444. "date_modified": "1436527638",
  445. "description": "test project #1",
  446. "fullname": "test",
  447. "url_path": "test",
  448. "id": 1,
  449. "milestones": {},
  450. "name": "test",
  451. "namespace": None,
  452. "parent": None,
  453. "priorities": {},
  454. "tags": ["infra"],
  455. "user": {
  456. "fullname": "PY C",
  457. "name": "pingou"
  458. }
  459. },
  460. {
  461. "access_groups": {
  462. "admin": [],
  463. "commit": [],
  464. "ticket": []
  465. },
  466. "access_users": {
  467. "admin": [],
  468. "commit": [],
  469. "owner": ["pingou"],
  470. "ticket": []
  471. },
  472. "close_status": [
  473. "Invalid",
  474. "Insufficient data",
  475. "Fixed",
  476. "Duplicate"
  477. ],
  478. "custom_keys": [],
  479. "date_created": "1436527638",
  480. "date_modified": "1436527638",
  481. "description": "test project #2",
  482. "fullname": "test2",
  483. "url_path": "test2",
  484. "id": 2,
  485. "milestones": {},
  486. "name": "test2",
  487. "namespace": None,
  488. "parent": None,
  489. "priorities": {},
  490. "tags": [],
  491. "user": {
  492. "fullname": "PY C",
  493. "name": "pingou"
  494. }
  495. },
  496. {
  497. "access_groups": {
  498. "admin": [],
  499. "commit": [],
  500. "ticket": []
  501. },
  502. "access_users": {
  503. "admin": [],
  504. "commit": [],
  505. "owner": ["pingou"],
  506. "ticket": []
  507. },
  508. "close_status": [
  509. "Invalid",
  510. "Insufficient data",
  511. "Fixed",
  512. "Duplicate"
  513. ],
  514. "custom_keys": [],
  515. "date_created": "1436527638",
  516. "date_modified": "1436527638",
  517. "description": "namespaced test project",
  518. "fullname": "somenamespace/test3",
  519. "url_path": "somenamespace/test3",
  520. "id": 3,
  521. "milestones": {},
  522. "name": "test3",
  523. "namespace": "somenamespace",
  524. "parent": None,
  525. "priorities": {},
  526. "tags": [],
  527. "user": {
  528. "fullname": "PY C",
  529. "name": "pingou"
  530. }
  531. }
  532. ],
  533. "total_projects": 3
  534. }
  535. self.assertDictEqual(data, expected_data)
  536. output = self.app.get('/api/0/projects?username=pingou')
  537. self.assertEqual(output.status_code, 200)
  538. data = json.loads(output.data)
  539. data['projects'][0]['date_created'] = "1436527638"
  540. data['projects'][0]['date_modified'] = "1436527638"
  541. data['projects'][1]['date_created'] = "1436527638"
  542. data['projects'][1]['date_modified'] = "1436527638"
  543. data['projects'][2]['date_created'] = "1436527638"
  544. data['projects'][2]['date_modified'] = "1436527638"
  545. expected_data = {
  546. "args": {
  547. "fork": None,
  548. "namespace": None,
  549. "owner": None,
  550. "pattern": None,
  551. "short": False,
  552. "tags": [],
  553. "username": "pingou"
  554. },
  555. "projects": [
  556. {
  557. "access_groups": {
  558. "admin": [],
  559. "commit": [],
  560. "ticket": []},
  561. "access_users": {
  562. "admin": [],
  563. "commit": [],
  564. "owner": ["pingou"],
  565. "ticket": []
  566. },
  567. "close_status": [
  568. "Invalid",
  569. "Insufficient data",
  570. "Fixed",
  571. "Duplicate"
  572. ],
  573. "custom_keys": [],
  574. "date_created": "1436527638",
  575. "date_modified": "1436527638",
  576. "description": "test project #1",
  577. "fullname": "test",
  578. "url_path": "test",
  579. "id": 1,
  580. "milestones": {},
  581. "name": "test",
  582. "namespace": None,
  583. "parent": None,
  584. "priorities": {},
  585. "tags": ["infra"],
  586. "user": {
  587. "fullname": "PY C",
  588. "name": "pingou"
  589. }
  590. },
  591. {
  592. "access_groups": {
  593. "admin": [],
  594. "commit": [],
  595. "ticket": []
  596. },
  597. "access_users": {
  598. "admin": [],
  599. "commit": [],
  600. "owner": ["pingou"],
  601. "ticket": []
  602. },
  603. "close_status": [
  604. "Invalid",
  605. "Insufficient data",
  606. "Fixed",
  607. "Duplicate"
  608. ],
  609. "custom_keys": [],
  610. "date_created": "1436527638",
  611. "date_modified": "1436527638",
  612. "description": "test project #2",
  613. "fullname": "test2",
  614. "url_path": "test2",
  615. "id": 2,
  616. "milestones": {},
  617. "name": "test2",
  618. "namespace": None,
  619. "parent": None,
  620. "priorities": {},
  621. "tags": [],
  622. "user": {
  623. "fullname": "PY C",
  624. "name": "pingou"
  625. }
  626. },
  627. {
  628. "access_groups": {
  629. "admin": [],
  630. "commit": [],
  631. "ticket": []},
  632. "access_users": {
  633. "admin": [],
  634. "commit": [],
  635. "owner": ["pingou"],
  636. "ticket": []},
  637. "close_status": [
  638. "Invalid",
  639. "Insufficient data",
  640. "Fixed",
  641. "Duplicate"
  642. ],
  643. "custom_keys": [],
  644. "date_created": "1436527638",
  645. "date_modified": "1436527638",
  646. "description": "namespaced test project",
  647. "fullname": "somenamespace/test3",
  648. "url_path": "somenamespace/test3",
  649. "id": 3,
  650. "milestones": {},
  651. "name": "test3",
  652. "namespace": "somenamespace",
  653. "parent": None,
  654. "priorities": {},
  655. "tags": [],
  656. "user": {
  657. "fullname": "PY C",
  658. "name": "pingou"
  659. }
  660. }
  661. ],
  662. "total_projects": 3
  663. }
  664. self.assertDictEqual(data, expected_data)
  665. output = self.app.get('/api/0/projects?username=pingou&tags=infra')
  666. self.assertEqual(output.status_code, 200)
  667. data = json.loads(output.data)
  668. data['projects'][0]['date_created'] = "1436527638"
  669. data['projects'][0]['date_modified'] = "1436527638"
  670. expected_data = {
  671. "args": {
  672. "fork": None,
  673. "namespace": None,
  674. "owner": None,
  675. "pattern": None,
  676. "short": False,
  677. "tags": ["infra"],
  678. "username": "pingou",
  679. },
  680. "projects": [{
  681. "access_groups": {
  682. "admin": [],
  683. "commit": [],
  684. "ticket": []
  685. },
  686. "access_users": {
  687. "admin": [],
  688. "commit": [],
  689. "owner": ["pingou"],
  690. "ticket": []},
  691. "close_status": [
  692. "Invalid",
  693. "Insufficient data",
  694. "Fixed",
  695. "Duplicate"],
  696. "custom_keys": [],
  697. "date_created": "1436527638",
  698. "date_modified": "1436527638",
  699. "description": "test project #1",
  700. "fullname": "test",
  701. "url_path": "test",
  702. "id": 1,
  703. "milestones": {},
  704. "name": "test",
  705. "namespace": None,
  706. "parent": None,
  707. "priorities": {},
  708. "tags": ["infra"],
  709. "user": {
  710. "fullname": "PY C",
  711. "name": "pingou"
  712. }
  713. }],
  714. "total_projects": 1
  715. }
  716. self.assertDictEqual(data, expected_data)
  717. output = self.app.get('/api/0/projects?namespace=somenamespace')
  718. self.assertEqual(output.status_code, 200)
  719. data = json.loads(output.data)
  720. data['projects'][0]['date_created'] = "1436527638"
  721. data['projects'][0]['date_modified'] = "1436527638"
  722. expected_data = {
  723. "args": {
  724. "fork": None,
  725. "owner": None,
  726. "namespace": "somenamespace",
  727. "pattern": None,
  728. "short": False,
  729. "tags": [],
  730. "username": None
  731. },
  732. "projects": [
  733. {
  734. "access_groups": {
  735. "admin": [],
  736. "commit": [],
  737. "ticket": []},
  738. "access_users": {
  739. "admin": [],
  740. "commit": [],
  741. "owner": ["pingou"],
  742. "ticket": []},
  743. "close_status": [
  744. "Invalid",
  745. "Insufficient data",
  746. "Fixed",
  747. "Duplicate"
  748. ],
  749. "custom_keys": [],
  750. "date_created": "1436527638",
  751. "date_modified": "1436527638",
  752. "description": "namespaced test project",
  753. "fullname": "somenamespace/test3",
  754. "url_path": "somenamespace/test3",
  755. "id": 3,
  756. "milestones": {},
  757. "name": "test3",
  758. "namespace": "somenamespace",
  759. "parent": None,
  760. "priorities": {},
  761. "tags": [],
  762. "user": {
  763. "fullname": "PY C",
  764. "name": "pingou"
  765. }
  766. }
  767. ],
  768. "total_projects": 1
  769. }
  770. self.assertDictEqual(data, expected_data)
  771. def test_api_project(self):
  772. """ Test the api_project method of the flask api. """
  773. tests.create_projects(self.session)
  774. # Check before adding
  775. repo = pagure.lib.get_authorized_project(self.session, 'test')
  776. self.assertEqual(repo.tags, [])
  777. # Adding a tag
  778. output = pagure.lib.update_tags(
  779. self.session, repo, 'infra', 'pingou',
  780. gitfolder=None)
  781. self.assertEqual(output, ['Project tagged with: infra'])
  782. # Check after adding
  783. repo = pagure.lib.get_authorized_project(self.session, 'test')
  784. self.assertEqual(len(repo.tags), 1)
  785. self.assertEqual(repo.tags_text, ['infra'])
  786. # Check the API
  787. # Non-existing project
  788. output = self.app.get('/api/0/random')
  789. self.assertEqual(output.status_code, 404)
  790. data = json.loads(output.data)
  791. self.assertDictEqual(
  792. data,
  793. {'error_code': 'ENOPROJECT', 'error': 'Project not found'}
  794. )
  795. # Existing project
  796. output = self.app.get('/api/0/test')
  797. self.assertEqual(output.status_code, 200)
  798. data = json.loads(output.data)
  799. data['date_created'] = "1436527638"
  800. data['date_modified'] = "1436527638"
  801. expected_data ={
  802. "access_groups": {
  803. "admin": [],
  804. "commit": [],
  805. "ticket": []
  806. },
  807. "access_users": {
  808. "admin": [],
  809. "commit": [],
  810. "owner": ["pingou"],
  811. "ticket": []},
  812. "close_status": [
  813. "Invalid",
  814. "Insufficient data",
  815. "Fixed",
  816. "Duplicate"
  817. ],
  818. "custom_keys": [],
  819. "date_created": "1436527638",
  820. "date_modified": "1436527638",
  821. "description": "test project #1",
  822. "fullname": "test",
  823. "url_path": "test",
  824. "id": 1,
  825. "milestones": {},
  826. "name": "test",
  827. "namespace": None,
  828. "parent": None,
  829. "priorities": {},
  830. "tags": ["infra"],
  831. "user": {
  832. "fullname": "PY C",
  833. "name": "pingou"
  834. }
  835. }
  836. self.assertDictEqual(data, expected_data)
  837. def test_api_project_group(self):
  838. """ Test the api_project method of the flask api. """
  839. tests.create_projects(self.session)
  840. repo = pagure.lib.get_authorized_project(self.session, 'test')
  841. # Adding a tag
  842. output = pagure.lib.update_tags(
  843. self.session, repo, 'infra', 'pingou',
  844. gitfolder=None)
  845. self.assertEqual(output, ['Project tagged with: infra'])
  846. # Check after adding
  847. repo = pagure.lib.get_authorized_project(self.session, 'test')
  848. self.assertEqual(len(repo.tags), 1)
  849. self.assertEqual(repo.tags_text, ['infra'])
  850. # Add a group to the project
  851. msg = pagure.lib.add_group(
  852. self.session,
  853. group_name='some_group',
  854. display_name='Some Group',
  855. description=None,
  856. group_type='bar',
  857. user='foo',
  858. is_admin=False,
  859. blacklist=[],
  860. )
  861. self.session.commit()
  862. project = pagure.lib.get_authorized_project(self.session, 'test')
  863. group = pagure.lib.search_groups(
  864. self.session, group_name='some_group')
  865. pagure.lib.add_group_to_project(
  866. self.session,
  867. project,
  868. new_group='some_group',
  869. user='pingou',
  870. access='commit',
  871. create=False,
  872. is_admin=True
  873. )
  874. self.session.commit()
  875. # Check the API
  876. # Existing project
  877. output = self.app.get('/api/0/test?expand_group=1')
  878. self.assertEqual(output.status_code, 200)
  879. data = json.loads(output.data)
  880. data['date_created'] = "1436527638"
  881. data['date_modified'] = "1436527638"
  882. expected_data ={
  883. "access_groups": {
  884. "admin": [],
  885. "commit": ["some_group"],
  886. "ticket": []
  887. },
  888. "access_users": {
  889. "admin": [],
  890. "commit": [],
  891. "owner": ["pingou"],
  892. "ticket": []},
  893. "close_status": [
  894. "Invalid",
  895. "Insufficient data",
  896. "Fixed",
  897. "Duplicate"
  898. ],
  899. "custom_keys": [],
  900. "date_created": "1436527638",
  901. "date_modified": "1436527638",
  902. "description": "test project #1",
  903. "fullname": "test",
  904. "url_path": "test",
  905. "group_details": {
  906. "some_group": [
  907. "foo"
  908. ]
  909. },
  910. "id": 1,
  911. "milestones": {},
  912. "name": "test",
  913. "namespace": None,
  914. "parent": None,
  915. "priorities": {},
  916. "tags": ["infra"],
  917. "user": {
  918. "fullname": "PY C",
  919. "name": "pingou"
  920. }
  921. }
  922. self.assertDictEqual(data, expected_data)
  923. def test_api_project_group_but_no_group(self):
  924. """ Test the api_project method of the flask api when asking for
  925. group details while there are none associated.
  926. """
  927. tests.create_projects(self.session)
  928. repo = pagure.lib.get_authorized_project(self.session, 'test')
  929. # Adding a tag
  930. output = pagure.lib.update_tags(
  931. self.session, repo, 'infra', 'pingou',
  932. gitfolder=None)
  933. self.assertEqual(output, ['Project tagged with: infra'])
  934. # Check after adding
  935. repo = pagure.lib.get_authorized_project(self.session, 'test')
  936. self.assertEqual(len(repo.tags), 1)
  937. self.assertEqual(repo.tags_text, ['infra'])
  938. # Check the API
  939. # Existing project
  940. output = self.app.get('/api/0/test?expand_group=0')
  941. self.assertEqual(output.status_code, 200)
  942. data = json.loads(output.data)
  943. data['date_created'] = "1436527638"
  944. data['date_modified'] = "1436527638"
  945. expected_data ={
  946. "access_groups": {
  947. "admin": [],
  948. "commit": [],
  949. "ticket": []
  950. },
  951. "access_users": {
  952. "admin": [],
  953. "commit": [],
  954. "owner": ["pingou"],
  955. "ticket": []},
  956. "close_status": [
  957. "Invalid",
  958. "Insufficient data",
  959. "Fixed",
  960. "Duplicate"
  961. ],
  962. "custom_keys": [],
  963. "date_created": "1436527638",
  964. "date_modified": "1436527638",
  965. "description": "test project #1",
  966. "fullname": "test",
  967. "url_path": "test",
  968. "id": 1,
  969. "milestones": {},
  970. "name": "test",
  971. "namespace": None,
  972. "parent": None,
  973. "priorities": {},
  974. "tags": ["infra"],
  975. "user": {
  976. "fullname": "PY C",
  977. "name": "pingou"
  978. }
  979. }
  980. self.assertDictEqual(data, expected_data)
  981. def test_api_projects_pagination(self):
  982. """ Test the api_projects method of the flask api with pagination. """
  983. tests.create_projects(self.session)
  984. output = self.app.get('/api/0/projects?page=1')
  985. self.assertEqual(output.status_code, 200)
  986. data = json.loads(output.data)
  987. for i in range(3):
  988. data['projects'][i]['date_created'] = "1436527638"
  989. data['projects'][i]['date_modified'] = "1436527638"
  990. expected_data = {
  991. "args": {
  992. "fork": None,
  993. "namespace": None,
  994. "owner": None,
  995. "page": 1,
  996. "per_page": 20,
  997. "pattern": None,
  998. "short": False,
  999. "tags": [],
  1000. "username": None
  1001. },
  1002. "pagination": {
  1003. "next": None,
  1004. "page": 1,
  1005. "pages": 1,
  1006. "per_page": 20,
  1007. "prev": None
  1008. },
  1009. "projects": [
  1010. {
  1011. "access_groups": {
  1012. "admin": [],
  1013. "commit": [],
  1014. "ticket": []},
  1015. "access_users": {
  1016. "admin": [],
  1017. "commit": [],
  1018. "owner": ["pingou"],
  1019. "ticket": []
  1020. },
  1021. "close_status": [
  1022. "Invalid",
  1023. "Insufficient data",
  1024. "Fixed",
  1025. "Duplicate"
  1026. ],
  1027. "custom_keys": [],
  1028. "date_created": "1436527638",
  1029. "date_modified": "1436527638",
  1030. "description": "test project #1",
  1031. "fullname": "test",
  1032. "url_path": "test",
  1033. "id": 1,
  1034. "milestones": {},
  1035. "name": "test",
  1036. "namespace": None,
  1037. "parent": None,
  1038. "priorities": {},
  1039. "tags": [],
  1040. "user": {
  1041. "fullname": "PY C",
  1042. "name": "pingou"
  1043. }
  1044. },
  1045. {
  1046. "access_groups": {
  1047. "admin": [],
  1048. "commit": [],
  1049. "ticket": []
  1050. },
  1051. "access_users": {
  1052. "admin": [],
  1053. "commit": [],
  1054. "owner": ["pingou"],
  1055. "ticket": []
  1056. },
  1057. "close_status": [
  1058. "Invalid",
  1059. "Insufficient data",
  1060. "Fixed",
  1061. "Duplicate"
  1062. ],
  1063. "custom_keys": [],
  1064. "date_created": "1436527638",
  1065. "date_modified": "1436527638",
  1066. "description": "test project #2",
  1067. "fullname": "test2",
  1068. "url_path": "test2",
  1069. "id": 2,
  1070. "milestones": {},
  1071. "name": "test2",
  1072. "namespace": None,
  1073. "parent": None,
  1074. "priorities": {},
  1075. "tags": [],
  1076. "user": {
  1077. "fullname": "PY C",
  1078. "name": "pingou"
  1079. }
  1080. },
  1081. {
  1082. "access_groups": {
  1083. "admin": [],
  1084. "commit": [],
  1085. "ticket": []},
  1086. "access_users": {
  1087. "admin": [],
  1088. "commit": [],
  1089. "owner": ["pingou"],
  1090. "ticket": []},
  1091. "close_status": [
  1092. "Invalid",
  1093. "Insufficient data",
  1094. "Fixed",
  1095. "Duplicate"
  1096. ],
  1097. "custom_keys": [],
  1098. "date_created": "1436527638",
  1099. "date_modified": "1436527638",
  1100. "description": "namespaced test project",
  1101. "fullname": "somenamespace/test3",
  1102. "url_path": "somenamespace/test3",
  1103. "id": 3,
  1104. "milestones": {},
  1105. "name": "test3",
  1106. "namespace": "somenamespace",
  1107. "parent": None,
  1108. "priorities": {},
  1109. "tags": [],
  1110. "user": {
  1111. "fullname": "PY C",
  1112. "name": "pingou"
  1113. }
  1114. }
  1115. ],
  1116. "total_projects": 3
  1117. }
  1118. # Test URLs
  1119. self.assertURLEqual(
  1120. data["pagination"].pop("first"),
  1121. "http://localhost/api/0/projects?per_page=20&page=1",
  1122. )
  1123. self.assertURLEqual(
  1124. data["pagination"].pop("last"),
  1125. "http://localhost/api/0/projects?per_page=20&page=1",
  1126. )
  1127. self.assertDictEqual(data, expected_data)
  1128. def test_api_projects_pagination_per_page(self):
  1129. """ Test the api_projects method of the flask api with pagination and
  1130. the `per_page` argument set. """
  1131. tests.create_projects(self.session)
  1132. output = self.app.get('/api/0/projects?page=2&per_page=2')
  1133. self.assertEqual(output.status_code, 200)
  1134. data = json.loads(output.data)
  1135. data['projects'][0]['date_created'] = "1436527638"
  1136. data['projects'][0]['date_modified'] = "1436527638"
  1137. expected_data = {
  1138. "args": {
  1139. "fork": None,
  1140. "namespace": None,
  1141. "owner": None,
  1142. "page": 2,
  1143. "per_page": 2,
  1144. "pattern": None,
  1145. "short": False,
  1146. "tags": [],
  1147. "username": None
  1148. },
  1149. "pagination": {
  1150. "next": None,
  1151. "page": 2,
  1152. "pages": 2,
  1153. "per_page": 2,
  1154. },
  1155. "projects": [
  1156. {
  1157. "access_groups": {
  1158. "admin": [],
  1159. "commit": [],
  1160. "ticket": []
  1161. },
  1162. "access_users": {
  1163. "admin": [],
  1164. "commit": [],
  1165. "owner": ["pingou"],
  1166. "ticket": []
  1167. },
  1168. "close_status": [
  1169. "Invalid",
  1170. "Insufficient data",
  1171. "Fixed",
  1172. "Duplicate"
  1173. ],
  1174. "custom_keys": [],
  1175. "date_created": "1436527638",
  1176. "date_modified": "1436527638",
  1177. "description": "namespaced test project",
  1178. "fullname": "somenamespace/test3",
  1179. "url_path": "somenamespace/test3",
  1180. "id": 3,
  1181. "milestones": {},
  1182. "name": "test3",
  1183. "namespace": "somenamespace",
  1184. "parent": None,
  1185. "priorities": {},
  1186. "tags": [],
  1187. "user": {
  1188. "fullname": "PY C",
  1189. "name": "pingou"
  1190. }
  1191. }
  1192. ],
  1193. "total_projects": 3
  1194. }
  1195. self.assertURLEqual(
  1196. data["pagination"].pop("first"),
  1197. "http://localhost/api/0/projects?per_page=2&page=1",
  1198. )
  1199. self.assertURLEqual(
  1200. data["pagination"].pop("prev"),
  1201. "http://localhost/api/0/projects?per_page=2&page=1",
  1202. )
  1203. self.assertURLEqual(
  1204. data["pagination"].pop("last"),
  1205. "http://localhost/api/0/projects?per_page=2&page=2",
  1206. )
  1207. self.assertDictEqual(data, expected_data)
  1208. def test_api_projects_pagination_invalid_page(self):
  1209. """ Test the api_projects method of the flask api when an invalid page
  1210. value is entered. """
  1211. tests.create_projects(self.session)
  1212. output = self.app.get('/api/0/projects?page=-3')
  1213. self.assertEqual(output.status_code, 400)
  1214. def test_api_projects_pagination_invalid_page_str(self):
  1215. """ Test the api_projects method of the flask api when an invalid type
  1216. for the page value is entered. """
  1217. tests.create_projects(self.session)
  1218. output = self.app.get('/api/0/projects?page=abcd')
  1219. self.assertEqual(output.status_code, 400)
  1220. def test_api_projects_pagination_invalid_per_page_too_low(self):
  1221. """ Test the api_projects method of the flask api when a per_page
  1222. value is below 1. """
  1223. tests.create_projects(self.session)
  1224. output = self.app.get('/api/0/projects?page=1&per_page=0')
  1225. self.assertEqual(output.status_code, 400)
  1226. error = json.loads(output.data)
  1227. self.assertEqual(
  1228. error['error'], 'The per_page value must be between 1 and 100')
  1229. def test_api_projects_pagination_invalid_per_page_too_high(self):
  1230. """ Test the api_projects method of the flask api when a per_page
  1231. value is above 100. """
  1232. tests.create_projects(self.session)
  1233. output = self.app.get('/api/0/projects?page=1&per_page=101')
  1234. self.assertEqual(output.status_code, 400)
  1235. error = json.loads(output.data)
  1236. self.assertEqual(
  1237. error['error'], 'The per_page value must be between 1 and 100')
  1238. def test_api_projects_pagination_invalid_per_page_str(self):
  1239. """ Test the api_projects method of the flask api when an invalid type
  1240. for the per_page value is entered. """
  1241. tests.create_projects(self.session)
  1242. output = self.app.get('/api/0/projects?page=1&per_page=abcd')
  1243. self.assertEqual(output.status_code, 400)
  1244. def test_api_projects_pagination_beyond_last_page(self):
  1245. """ Test the api_projects method of the flask api when a page value
  1246. that is larger than the last page is entered. """
  1247. tests.create_projects(self.session)
  1248. output = self.app.get('/api/0/projects?page=99999')
  1249. self.assertEqual(output.status_code, 200)
  1250. data = json.loads(output.data)
  1251. self.assertURLEqual(
  1252. data["pagination"].pop("first"),
  1253. "http://localhost/api/0/projects?per_page=20&page=1",
  1254. )
  1255. self.assertURLEqual(
  1256. data["pagination"].pop("last"),
  1257. "http://localhost/api/0/projects?per_page=20&page=1",
  1258. )
  1259. self.assertURLEqual(
  1260. data["pagination"].pop("prev"),
  1261. "http://localhost/api/0/projects?per_page=20&page=99998",
  1262. )
  1263. self.assertEqual(
  1264. data,
  1265. {
  1266. "args": {
  1267. "fork": None,
  1268. "namespace": None,
  1269. "owner": None,
  1270. "page": 99999,
  1271. "pattern": None,
  1272. "per_page": 20,
  1273. "short": False,
  1274. "tags": [],
  1275. "username": None
  1276. },
  1277. "pagination": {
  1278. "next": None,
  1279. "page": 99999,
  1280. "pages": 1,
  1281. "per_page": 20,
  1282. },
  1283. "projects": [],
  1284. "total_projects": 3
  1285. }
  1286. )
  1287. def test_api_modify_project_main_admin(self):
  1288. """ Test the api_modify_project method of the flask api when the
  1289. request is to change the main_admin of the project. """
  1290. tests.create_projects(self.session)
  1291. tests.create_tokens(self.session, project_id=None)
  1292. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1293. headers = {'Authorization': 'token aaabbbcccddd'}
  1294. output = self.app.patch(
  1295. '/api/0/test', headers=headers,
  1296. data={'main_admin': 'foo'})
  1297. self.assertEqual(output.status_code, 200)
  1298. data = json.loads(output.get_data(as_text=True))
  1299. data['date_created'] = '1496338274'
  1300. data['date_modified'] = '1496338274'
  1301. expected_output = {
  1302. "access_groups": {
  1303. "admin": [],
  1304. "commit": [],
  1305. "ticket": []
  1306. },
  1307. "access_users": {
  1308. "admin": [],
  1309. "commit": [],
  1310. "owner": [
  1311. "foo"
  1312. ],
  1313. "ticket": []
  1314. },
  1315. "close_status": [
  1316. "Invalid",
  1317. "Insufficient data",
  1318. "Fixed",
  1319. "Duplicate"
  1320. ],
  1321. "custom_keys": [],
  1322. "date_created": "1496338274",
  1323. "date_modified": "1496338274",
  1324. "description": "test project #1",
  1325. "fullname": "test",
  1326. "url_path": "test",
  1327. "id": 1,
  1328. "milestones": {},
  1329. "name": "test",
  1330. "namespace": None,
  1331. "parent": None,
  1332. "priorities": {},
  1333. "tags": [],
  1334. "user": {
  1335. "default_email": "foo@bar.com",
  1336. "emails": [
  1337. "foo@bar.com"
  1338. ],
  1339. "fullname": "foo bar",
  1340. "name": "foo"
  1341. }
  1342. }
  1343. self.assertEqual(data, expected_output)
  1344. def test_api_modify_project_main_admin_retain_access(self):
  1345. """ Test the api_modify_project method of the flask api when the
  1346. request is to change the main_admin of the project and retain_access
  1347. is true. """
  1348. tests.create_projects(self.session)
  1349. tests.create_tokens(self.session, project_id=None)
  1350. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1351. headers = {'Authorization': 'token aaabbbcccddd'}
  1352. output = self.app.patch(
  1353. '/api/0/test', headers=headers,
  1354. data={'main_admin': 'foo', 'retain_access': True})
  1355. self.assertEqual(output.status_code, 200)
  1356. data = json.loads(output.get_data(as_text=True))
  1357. data['date_created'] = '1496338274'
  1358. data['date_modified'] = '1496338274'
  1359. expected_output = {
  1360. "access_groups": {
  1361. "admin": [],
  1362. "commit": [],
  1363. "ticket": []
  1364. },
  1365. "access_users": {
  1366. "admin": [
  1367. "pingou"
  1368. ],
  1369. "commit": [],
  1370. "owner": [
  1371. "foo"
  1372. ],
  1373. "ticket": []
  1374. },
  1375. "close_status": [
  1376. "Invalid",
  1377. "Insufficient data",
  1378. "Fixed",
  1379. "Duplicate"
  1380. ],
  1381. "custom_keys": [],
  1382. "date_created": "1496338274",
  1383. "date_modified": "1496338274",
  1384. "description": "test project #1",
  1385. "fullname": "test",
  1386. "url_path": "test",
  1387. "id": 1,
  1388. "milestones": {},
  1389. "name": "test",
  1390. "namespace": None,
  1391. "parent": None,
  1392. "priorities": {},
  1393. "tags": [],
  1394. "user": {
  1395. "default_email": "foo@bar.com",
  1396. "emails": [
  1397. "foo@bar.com"
  1398. ],
  1399. "fullname": "foo bar",
  1400. "name": "foo"
  1401. }
  1402. }
  1403. self.assertEqual(data, expected_output)
  1404. def test_api_modify_project_main_admin_retain_access_already_user(self):
  1405. """ Test the api_modify_project method of the flask api when the
  1406. request is to change the main_admin of the project and retain_access
  1407. is true and the user becoming the main_admin already has access. """
  1408. tests.create_projects(self.session)
  1409. tests.create_tokens(self.session, project_id=None)
  1410. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1411. headers = {'Authorization': 'token aaabbbcccddd'}
  1412. project = pagure.lib._get_project(self.session, 'test')
  1413. pagure.lib.add_user_to_project(
  1414. self.session, project,
  1415. new_user='foo',
  1416. user='pingou',
  1417. access='commit'
  1418. )
  1419. self.session.commit()
  1420. output = self.app.patch(
  1421. '/api/0/test', headers=headers,
  1422. data={'main_admin': 'foo', 'retain_access': True})
  1423. self.assertEqual(output.status_code, 200)
  1424. data = json.loads(output.get_data(as_text=True))
  1425. data['date_created'] = '1496338274'
  1426. data['date_modified'] = '1496338274'
  1427. expected_output = {
  1428. "access_groups": {
  1429. "admin": [],
  1430. "commit": [],
  1431. "ticket": []
  1432. },
  1433. "access_users": {
  1434. "admin": [
  1435. "pingou"
  1436. ],
  1437. "commit": [],
  1438. "owner": [
  1439. "foo"
  1440. ],
  1441. "ticket": []
  1442. },
  1443. "close_status": [
  1444. "Invalid",
  1445. "Insufficient data",
  1446. "Fixed",
  1447. "Duplicate"
  1448. ],
  1449. "custom_keys": [],
  1450. "date_created": "1496338274",
  1451. "date_modified": "1496338274",
  1452. "description": "test project #1",
  1453. "fullname": "test",
  1454. "url_path": "test",
  1455. "id": 1,
  1456. "milestones": {},
  1457. "name": "test",
  1458. "namespace": None,
  1459. "parent": None,
  1460. "priorities": {},
  1461. "tags": [],
  1462. "user": {
  1463. "default_email": "foo@bar.com",
  1464. "emails": [
  1465. "foo@bar.com"
  1466. ],
  1467. "fullname": "foo bar",
  1468. "name": "foo"
  1469. }
  1470. }
  1471. self.assertEqual(data, expected_output)
  1472. def test_api_modify_project_main_admin_json(self):
  1473. """ Test the api_modify_project method of the flask api when the
  1474. request is to change the main_admin of the project using JSON. """
  1475. tests.create_projects(self.session)
  1476. tests.create_tokens(self.session, project_id=None)
  1477. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1478. headers = {'Authorization': 'token aaabbbcccddd',
  1479. 'Content-Type': 'application/json'}
  1480. output = self.app.patch(
  1481. '/api/0/test', headers=headers,
  1482. data=json.dumps({'main_admin': 'foo'}))
  1483. self.assertEqual(output.status_code, 200)
  1484. data = json.loads(output.get_data(as_text=True))
  1485. data['date_created'] = '1496338274'
  1486. data['date_modified'] = '1496338274'
  1487. expected_output = {
  1488. "access_groups": {
  1489. "admin": [],
  1490. "commit": [],
  1491. "ticket": []
  1492. },
  1493. "access_users": {
  1494. "admin": [],
  1495. "commit": [],
  1496. "owner": [
  1497. "foo"
  1498. ],
  1499. "ticket": []
  1500. },
  1501. "close_status": [
  1502. "Invalid",
  1503. "Insufficient data",
  1504. "Fixed",
  1505. "Duplicate"
  1506. ],
  1507. "custom_keys": [],
  1508. "date_created": "1496338274",
  1509. "date_modified": "1496338274",
  1510. "description": "test project #1",
  1511. "fullname": "test",
  1512. "url_path": "test",
  1513. "id": 1,
  1514. "milestones": {},
  1515. "name": "test",
  1516. "namespace": None,
  1517. "parent": None,
  1518. "priorities": {},
  1519. "tags": [],
  1520. "user": {
  1521. "default_email": "foo@bar.com",
  1522. "emails": [
  1523. "foo@bar.com"
  1524. ],
  1525. "fullname": "foo bar",
  1526. "name": "foo"
  1527. }
  1528. }
  1529. self.assertEqual(data, expected_output)
  1530. @patch.dict('pagure.config.config', {'PAGURE_ADMIN_USERS': 'foo'})
  1531. def test_api_modify_project_main_admin_as_site_admin(self):
  1532. """ Test the api_modify_project method of the flask api when the
  1533. request is to change the main_admin of the project and the user is a
  1534. Pagure site admin. """
  1535. tests.create_projects(self.session)
  1536. tests.create_tokens(self.session, user_id=2, project_id=None)
  1537. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1538. headers = {'Authorization': 'token aaabbbcccddd'}
  1539. output = self.app.patch(
  1540. '/api/0/test', headers=headers,
  1541. data={'main_admin': 'foo'})
  1542. self.assertEqual(output.status_code, 200)
  1543. data = json.loads(output.get_data(as_text=True))
  1544. data['date_created'] = '1496338274'
  1545. data['date_modified'] = '1496338274'
  1546. expected_output = {
  1547. "access_groups": {
  1548. "admin": [],
  1549. "commit": [],
  1550. "ticket": []
  1551. },
  1552. "access_users": {
  1553. "admin": [],
  1554. "commit": [],
  1555. "owner": [
  1556. "foo"
  1557. ],
  1558. "ticket": []
  1559. },
  1560. "close_status": [
  1561. "Invalid",
  1562. "Insufficient data",
  1563. "Fixed",
  1564. "Duplicate"
  1565. ],
  1566. "custom_keys": [],
  1567. "date_created": "1496338274",
  1568. "date_modified": "1496338274",
  1569. "description": "test project #1",
  1570. "fullname": "test",
  1571. "url_path": "test",
  1572. "id": 1,
  1573. "milestones": {},
  1574. "name": "test",
  1575. "namespace": None,
  1576. "parent": None,
  1577. "priorities": {},
  1578. "tags": [],
  1579. "user": {
  1580. "default_email": "foo@bar.com",
  1581. "emails": [
  1582. "foo@bar.com"
  1583. ],
  1584. "fullname": "foo bar",
  1585. "name": "foo"
  1586. }
  1587. }
  1588. self.assertEqual(data, expected_output)
  1589. def test_api_modify_project_main_admin_not_main_admin(self):
  1590. """ Test the api_modify_project method of the flask api when the
  1591. requester is not the main_admin of the project and requests to change
  1592. the main_admin.
  1593. """
  1594. tests.create_projects(self.session)
  1595. project_user = pagure.lib.model.ProjectUser(
  1596. project_id=1,
  1597. user_id=2,
  1598. access='admin',
  1599. )
  1600. self.session.add(project_user)
  1601. self.session.commit()
  1602. tests.create_tokens(self.session, project_id=None, user_id=2)
  1603. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1604. headers = {'Authorization': 'token aaabbbcccddd'}
  1605. output = self.app.patch(
  1606. '/api/0/test', headers=headers,
  1607. data={'main_admin': 'foo'})
  1608. self.assertEqual(output.status_code, 401)
  1609. expected_error = {
  1610. 'error': ('Only the main admin can set the main admin of a '
  1611. 'project'),
  1612. 'error_code': 'ENOTMAINADMIN'
  1613. }
  1614. self.assertEqual(
  1615. json.loads(output.get_data(as_text=True)), expected_error)
  1616. def test_api_modify_project_not_admin(self):
  1617. """ Test the api_modify_project method of the flask api when the
  1618. requester is not an admin of the project.
  1619. """
  1620. tests.create_projects(self.session)
  1621. tests.create_tokens(self.session, project_id=None, user_id=2)
  1622. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1623. headers = {'Authorization': 'token aaabbbcccddd'}
  1624. output = self.app.patch(
  1625. '/api/0/test', headers=headers,
  1626. data={'main_admin': 'foo'})
  1627. self.assertEqual(output.status_code, 401)
  1628. expected_error = {
  1629. 'error': 'You are not allowed to modify this project',
  1630. 'error_code': 'EMODIFYPROJECTNOTALLOWED'
  1631. }
  1632. self.assertEqual(
  1633. json.loads(output.get_data(as_text=True)), expected_error)
  1634. def test_api_modify_project_invalid_request(self):
  1635. """ Test the api_modify_project method of the flask api when the
  1636. request data is invalid.
  1637. """
  1638. tests.create_projects(self.session)
  1639. tests.create_tokens(self.session, project_id=None)
  1640. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1641. headers = {'Authorization': 'token aaabbbcccddd'}
  1642. output = self.app.patch(
  1643. '/api/0/test', headers=headers,
  1644. data='invalid')
  1645. self.assertEqual(output.status_code, 400)
  1646. expected_error = {
  1647. 'error': 'Invalid or incomplete input submitted',
  1648. 'error_code': 'EINVALIDREQ'
  1649. }
  1650. self.assertEqual(
  1651. json.loads(output.get_data(as_text=True)), expected_error)
  1652. def test_api_modify_project_invalid_keys(self):
  1653. """ Test the api_modify_project method of the flask api when the
  1654. request data contains an invalid key.
  1655. """
  1656. tests.create_projects(self.session)
  1657. tests.create_tokens(self.session, project_id=None)
  1658. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1659. headers = {'Authorization': 'token aaabbbcccddd'}
  1660. output = self.app.patch(
  1661. '/api/0/test', headers=headers,
  1662. data={'invalid': 'invalid'})
  1663. self.assertEqual(output.status_code, 400)
  1664. expected_error = {
  1665. 'error': 'Invalid or incomplete input submitted',
  1666. 'error_code': 'EINVALIDREQ'
  1667. }
  1668. self.assertEqual(
  1669. json.loads(output.get_data(as_text=True)), expected_error)
  1670. def test_api_modify_project_invalid_new_main_admin(self):
  1671. """ Test the api_modify_project method of the flask api when the
  1672. request is to change the main_admin of the project to a main_admin
  1673. that doesn't exist.
  1674. """
  1675. tests.create_projects(self.session)
  1676. tests.create_tokens(self.session, project_id=None)
  1677. tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
  1678. headers = {'Authorization': 'token aaabbbcccddd'}
  1679. output = self.app.patch(
  1680. '/api/0/test', headers=headers,
  1681. data={'main_admin': 'tbrady'})
  1682. self.assertEqual(output.status_code, 400)
  1683. expected_error = {
  1684. 'error': 'No such user found',
  1685. 'error_code': 'ENOUSER'
  1686. }
  1687. self.assertEqual(
  1688. json.loads(output.get_data(as_text=True)), expected_error)
  1689. def test_api_project_watchers(self):
  1690. """ Test the api_project_watchers method of the flask api. """
  1691. tests.create_projects(self.session)
  1692. # The user is not logged in and the owner is watching issues implicitly
  1693. output = self.app.get('/api/0/test/watchers')
  1694. self.assertEqual(output.status_code, 200)
  1695. expected_data = {
  1696. "total_watchers": 1,
  1697. "watchers": {
  1698. "pingou": [
  1699. "issues"
  1700. ]
  1701. }
  1702. }
  1703. self.assertDictEqual(json.loads(output.data), expected_data)
  1704. user = tests.FakeUser(username='pingou')
  1705. with tests.user_set(self.app.application, user):
  1706. # Non-existing project
  1707. output = self.app.get('/api/0/random/watchers')
  1708. self.assertEqual(output.status_code, 404)
  1709. data = json.loads(output.data)
  1710. self.assertDictEqual(
  1711. data,
  1712. {'error_code': 'ENOPROJECT', 'error': 'Project not found'}
  1713. )
  1714. # The owner is watching issues implicitly
  1715. output = self.app.get('/api/0/test/watchers')
  1716. self.assertEqual(output.status_code, 200)
  1717. expected_data = {
  1718. "total_watchers": 1,
  1719. "watchers": {
  1720. "pingou": [
  1721. "issues"
  1722. ]
  1723. }
  1724. }
  1725. self.assertDictEqual(json.loads(output.data), expected_data)
  1726. project = pagure.lib.get_authorized_project(self.session, 'test')
  1727. # The owner is watching issues and commits explicitly
  1728. pagure.lib.update_watch_status(
  1729. self.session, project, 'pingou', '3')
  1730. self.session.commit()
  1731. output = self.app.get('/api/0/test/watchers')
  1732. self.assertEqual(output.status_code, 200)
  1733. expected_data = {
  1734. "total_watchers": 1,
  1735. "watchers": {
  1736. "pingou": [
  1737. "issues",
  1738. "commits"
  1739. ]
  1740. }
  1741. }
  1742. self.assertDictEqual(json.loads(output.data), expected_data)
  1743. # The owner is watching issues explicitly
  1744. pagure.lib.update_watch_status(
  1745. self.session, project, 'pingou', '1')
  1746. self.session.commit()
  1747. output = self.app.get('/api/0/test/watchers')
  1748. self.assertEqual(output.status_code, 200)
  1749. expected_data = {
  1750. "total_watchers": 1,
  1751. "watchers": {
  1752. "pingou": [
  1753. "issues"
  1754. ]
  1755. }
  1756. }
  1757. self.assertDictEqual(json.loads(output.data), expected_data)
  1758. # The owner is watching commits explicitly
  1759. pagure.lib.update_watch_status(
  1760. self.session, project, 'pingou', '2')
  1761. self.session.commit()
  1762. output = self.app.get('/api/0/test/watchers')
  1763. self.assertEqual(output.status_code, 200)
  1764. expected_data = {
  1765. "total_watchers": 1,
  1766. "watchers": {
  1767. "pingou": [
  1768. "commits"
  1769. ]
  1770. }
  1771. }
  1772. self.assertDictEqual(json.loads(output.data), expected_data)
  1773. # The owner is watching commits explicitly and foo is watching
  1774. # issues implicitly
  1775. project_user = pagure.lib.model.ProjectUser(
  1776. project_id=project.id,
  1777. user_id=2,
  1778. access='commit',
  1779. )
  1780. pagure.lib.update_watch_status(
  1781. self.session, project, 'pingou', '2')
  1782. self.session.add(project_user)
  1783. self.session.commit()
  1784. output = self.app.get('/api/0/test/watchers')
  1785. self.assertEqual(output.status_code, 200)
  1786. expected_data = {
  1787. "total_watchers": 2,
  1788. "watchers": {
  1789. "foo": ["issues"],
  1790. "pingou": ["commits"]
  1791. }
  1792. }
  1793. self.assertDictEqual(json.loads(output.data), expected_data)
  1794. # The owner and foo are watching issues implicitly
  1795. pagure.lib.update_watch_status(
  1796. self.session, project, 'pingou', '-1')
  1797. self.session.commit()
  1798. output = self.app.get('/api/0/test/watchers')
  1799. self.assertEqual(output.status_code, 200)
  1800. expected_data = {
  1801. "total_watchers": 2,
  1802. "watchers": {
  1803. "foo": ["issues"],
  1804. "pingou": ["issues"]
  1805. }
  1806. }
  1807. self.assertDictEqual(json.loads(output.data), expected_data)
  1808. # The owner and foo through group membership are watching issues
  1809. # implicitly
  1810. pagure.lib.update_watch_status(
  1811. self.session, project, 'pingou', '-1')
  1812. project_membership = self.session.query(
  1813. pagure.lib.model.ProjectUser).filter_by(
  1814. user_id=2, project_id=project.id).one()
  1815. self.session.delete(project_membership)
  1816. self.session.commit()
  1817. msg = pagure.lib.add_group(
  1818. self.session,
  1819. group_name='some_group',
  1820. display_name='Some Group',
  1821. description=None,
  1822. group_type='bar',
  1823. user='pingou',
  1824. is_admin=False,
  1825. blacklist=[],
  1826. )
  1827. self.session.commit()
  1828. project = pagure.lib.get_authorized_project(self.session, 'test')
  1829. group = pagure.lib.search_groups(
  1830. self.session, group_name='some_group')
  1831. pagure.lib.add_user_to_group(
  1832. self.session, 'foo', group, 'pingou', False)
  1833. pagure.lib.add_group_to_project(
  1834. self.session,
  1835. project,
  1836. new_group='some_group',
  1837. user='pingou',
  1838. access='commit',
  1839. create=False,
  1840. is_admin=True
  1841. )
  1842. self.session.commit()
  1843. output = self.app.get('/api/0/test/watchers')
  1844. self.assertEqual(output.status_code, 200)
  1845. expected_data = {
  1846. "total_watchers": 2,
  1847. "watchers": {
  1848. "@some_group": ["issues"],
  1849. "pingou": ["issues"]
  1850. }
  1851. }
  1852. self.assertDictEqual(json.loads(output.data), expected_data)
  1853. # The owner is watching issues implicitly and foo will be watching
  1854. # commits explicitly but is in a group with commit access
  1855. pagure.lib.update_watch_status(
  1856. self.session, project, 'pingou', '-1')
  1857. pagure.lib.update_watch_status(
  1858. self.session, project, 'foo', '2')
  1859. self.session.commit()
  1860. output = self.app.get('/api/0/test/watchers')
  1861. self.assertEqual(output.status_code, 200)
  1862. expected_data = {
  1863. "total_watchers": 3,
  1864. "watchers": {
  1865. "@some_group": ["issues"],
  1866. "foo": ["commits"],
  1867. "pingou": ["issues"]
  1868. }
  1869. }
  1870. self.assertDictEqual(json.loads(output.data), expected_data)
  1871. def test_api_new_project(self):
  1872. """ Test the api_new_project method of the flask api. """
  1873. tests.create_projects(self.session)
  1874. tests.create_projects_git(os.path.join(self.path, 'tickets'))
  1875. tests.create_tokens(self.session)
  1876. tests.create_tokens_acl(self.session)
  1877. headers = {'Authorization': 'token foo_token'}
  1878. # Invalid token
  1879. output = self.app.post('/api/0/new', headers=headers)
  1880. self.assertEqual(output.status_code, 401)
  1881. data = json.loads(output.data)
  1882. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  1883. self.assertEqual(
  1884. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  1885. self.assertEqual(
  1886. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  1887. headers = {'Authorization': 'token aaabbbcccddd'}
  1888. # No input
  1889. output = self.app.post('/api/0/new', headers=headers)
  1890. self.assertEqual(output.status_code, 400)
  1891. data = json.loads(output.data)
  1892. self.assertDictEqual(
  1893. data,
  1894. {
  1895. "error": "Invalid or incomplete input submitted",
  1896. "error_code": "EINVALIDREQ",
  1897. "errors": {
  1898. "name": ["This field is required."],
  1899. "description": ["This field is required."]
  1900. }
  1901. }
  1902. )
  1903. data = {
  1904. 'name': 'test',
  1905. }
  1906. # Incomplete request
  1907. output = self.app.post(
  1908. '/api/0/new', data=data, headers=headers)
  1909. self.assertEqual(output.status_code, 400)
  1910. data = json.loads(output.data)
  1911. self.assertDictEqual(
  1912. data,
  1913. {
  1914. "error": "Invalid or incomplete input submitted",
  1915. "error_code": "EINVALIDREQ",
  1916. "errors": {"description": ["This field is required."]}
  1917. }
  1918. )
  1919. data = {
  1920. 'name': 'test',
  1921. 'description': 'Just a small test project',
  1922. }
  1923. # Valid request but repo already exists
  1924. output = self.app.post(
  1925. '/api/0/new/', data=data, headers=headers)
  1926. self.assertEqual(output.status_code, 400)
  1927. data = json.loads(output.data)
  1928. self.assertDictEqual(
  1929. data,
  1930. {
  1931. "error": "It is not possible to create the repo \"test\"",
  1932. "error_code": "ENOCODE"
  1933. }
  1934. )
  1935. data = {
  1936. 'name': 'test_42',
  1937. 'description': 'Just another small test project',
  1938. }
  1939. # Valid request
  1940. output = self.app.post(
  1941. '/api/0/new/', data=data, headers=headers)
  1942. self.assertEqual(output.status_code, 200)
  1943. data = json.loads(output.data)
  1944. self.assertDictEqual(
  1945. data,
  1946. {'message': 'Project "test_42" created'}
  1947. )
  1948. @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
  1949. def test_api_new_project_private(self):
  1950. """ Test the api_new_project method of the flask api to create
  1951. a private project. """
  1952. tests.create_projects(self.session)
  1953. tests.create_projects_git(os.path.join(self.path, 'tickets'))
  1954. tests.create_tokens(self.session)
  1955. tests.create_tokens_acl(self.session)
  1956. headers = {'Authorization': 'token aaabbbcccddd'}
  1957. data = {
  1958. 'name': 'test',
  1959. 'description': 'Just a small test project',
  1960. 'private': True,
  1961. }
  1962. # Valid request
  1963. output = self.app.post(
  1964. '/api/0/new/', data=data, headers=headers)
  1965. self.assertEqual(output.status_code, 200)
  1966. data = json.loads(output.data)
  1967. self.assertDictEqual(
  1968. data,
  1969. {'message': 'Project "pingou/test" created'}
  1970. )
  1971. def test_api_new_project_user_token(self):
  1972. """ Test the api_new_project method of the flask api. """
  1973. tests.create_projects(self.session)
  1974. tests.create_projects_git(os.path.join(self.path, 'tickets'))
  1975. tests.create_tokens(self.session, project_id=None)
  1976. tests.create_tokens_acl(self.session)
  1977. headers = {'Authorization': 'token foo_token'}
  1978. # Invalid token
  1979. output = self.app.post('/api/0/new', headers=headers)
  1980. self.assertEqual(output.status_code, 401)
  1981. data = json.loads(output.data)
  1982. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  1983. self.assertEqual(
  1984. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  1985. self.assertEqual(
  1986. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  1987. headers = {'Authorization': 'token aaabbbcccddd'}
  1988. # No input
  1989. output = self.app.post('/api/0/new', headers=headers)
  1990. self.assertEqual(output.status_code, 400)
  1991. data = json.loads(output.data)
  1992. self.assertDictEqual(
  1993. data,
  1994. {
  1995. "error": "Invalid or incomplete input submitted",
  1996. "error_code": "EINVALIDREQ",
  1997. "errors": {
  1998. "name": ["This field is required."],
  1999. "description": ["This field is required."]
  2000. }
  2001. }
  2002. )
  2003. data = {
  2004. 'name': 'test',
  2005. }
  2006. # Incomplete request
  2007. output = self.app.post(
  2008. '/api/0/new', data=data, headers=headers)
  2009. self.assertEqual(output.status_code, 400)
  2010. data = json.loads(output.data)
  2011. self.assertDictEqual(
  2012. data,
  2013. {
  2014. "error": "Invalid or incomplete input submitted",
  2015. "error_code": "EINVALIDREQ",
  2016. "errors": {"description": ["This field is required."]}
  2017. }
  2018. )
  2019. data = {
  2020. 'name': 'test',
  2021. 'description': 'Just a small test project',
  2022. }
  2023. # Valid request but repo already exists
  2024. output = self.app.post(
  2025. '/api/0/new/', data=data, headers=headers)
  2026. self.assertEqual(output.status_code, 400)
  2027. data = json.loads(output.data)
  2028. self.assertDictEqual(
  2029. data,
  2030. {
  2031. "error": "It is not possible to create the repo \"test\"",
  2032. "error_code": "ENOCODE"
  2033. }
  2034. )
  2035. data = {
  2036. 'name': 'test_42',
  2037. 'description': 'Just another small test project',
  2038. }
  2039. # Valid request
  2040. output = self.app.post(
  2041. '/api/0/new/', data=data, headers=headers)
  2042. self.assertEqual(output.status_code, 200)
  2043. data = json.loads(output.data)
  2044. self.assertDictEqual(
  2045. data,
  2046. {'message': 'Project "test_42" created'}
  2047. )
  2048. # Project with a namespace
  2049. pagure.config.config['ALLOWED_PREFIX'] = ['rpms']
  2050. data = {
  2051. 'name': 'test_42',
  2052. 'namespace': 'pingou',
  2053. 'description': 'Just another small test project',
  2054. }
  2055. # Invalid namespace
  2056. output = self.app.post(
  2057. '/api/0/new/', data=data, headers=headers)
  2058. self.assertEqual(output.status_code, 400)
  2059. data = json.loads(output.data)
  2060. self.assertDictEqual(
  2061. data,
  2062. {
  2063. "error": "Invalid or incomplete input submitted",
  2064. "error_code": "EINVALIDREQ",
  2065. "errors": {
  2066. "namespace": [
  2067. "Not a valid choice"
  2068. ]
  2069. }
  2070. }
  2071. )
  2072. data = {
  2073. 'name': 'test_42',
  2074. 'namespace': 'rpms',
  2075. 'description': 'Just another small test project',
  2076. }
  2077. # All good
  2078. output = self.app.post(
  2079. '/api/0/new/', data=data, headers=headers)
  2080. self.assertEqual(output.status_code, 200)
  2081. data = json.loads(output.data)
  2082. self.assertDictEqual(
  2083. data,
  2084. {'message': 'Project "rpms/test_42" created'}
  2085. )
  2086. @patch.dict('pagure.config.config', {'USER_NAMESPACE': True})
  2087. def test_api_new_project_user_ns(self):
  2088. """ Test the api_new_project method of the flask api. """
  2089. tests.create_projects(self.session)
  2090. tests.create_projects_git(os.path.join(self.path, 'tickets'))
  2091. tests.create_tokens(self.session)
  2092. tests.create_tokens_acl(self.session)
  2093. headers = {'Authorization': 'token aaabbbcccddd'}
  2094. # Create a project with the user namespace feature on
  2095. data = {
  2096. 'name': 'testproject',
  2097. 'description': 'Just another small test project',
  2098. }
  2099. # Valid request
  2100. output = self.app.post(
  2101. '/api/0/new/', data=data, headers=headers)
  2102. self.assertEqual(output.status_code, 200)
  2103. data = json.loads(output.data)
  2104. self.assertDictEqual(
  2105. data,
  2106. {'message': 'Project "pingou/testproject" created'}
  2107. )
  2108. # Create a project with a namespace and the user namespace feature on
  2109. data = {
  2110. 'name': 'testproject2',
  2111. 'namespace': 'testns',
  2112. 'description': 'Just another small test project',
  2113. }
  2114. # Valid request
  2115. with patch.dict('pagure.config.config', {'ALLOWED_PREFIX': ['testns']}):
  2116. output = self.app.post(
  2117. '/api/0/new/', data=data, headers=headers)
  2118. self.assertEqual(output.status_code, 200)
  2119. data = json.loads(output.data)
  2120. self.assertDictEqual(
  2121. data,
  2122. {'message': 'Project "testns/testproject2" created'}
  2123. )
  2124. def test_api_fork_project(self):
  2125. """ Test the api_fork_project method of the flask api. """
  2126. tests.create_projects(self.session)
  2127. for folder in ['docs', 'tickets', 'requests', 'repos']:
  2128. tests.create_projects_git(
  2129. os.path.join(self.path, folder), bare=True)
  2130. tests.create_tokens(self.session)
  2131. tests.create_tokens_acl(self.session)
  2132. headers = {'Authorization': 'token foo_token'}
  2133. # Invalid token
  2134. output = self.app.post('/api/0/fork', headers=headers)
  2135. self.assertEqual(output.status_code, 401)
  2136. data = json.loads(output.data)
  2137. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  2138. self.assertEqual(
  2139. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  2140. self.assertEqual(
  2141. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  2142. headers = {'Authorization': 'token aaabbbcccddd'}
  2143. # No input
  2144. output = self.app.post('/api/0/fork', headers=headers)
  2145. self.assertEqual(output.status_code, 400)
  2146. data = json.loads(output.data)
  2147. self.assertDictEqual(
  2148. data,
  2149. {
  2150. "error": "Invalid or incomplete input submitted",
  2151. "error_code": "EINVALIDREQ",
  2152. "errors": {"repo": ["This field is required."]}
  2153. }
  2154. )
  2155. data = {
  2156. 'name': 'test',
  2157. }
  2158. # Incomplete request
  2159. output = self.app.post(
  2160. '/api/0/fork', data=data, headers=headers)
  2161. self.assertEqual(output.status_code, 400)
  2162. data = json.loads(output.data)
  2163. self.assertDictEqual(
  2164. data,
  2165. {
  2166. "error": "Invalid or incomplete input submitted",
  2167. "error_code": "EINVALIDREQ",
  2168. "errors": {"repo": ["This field is required."]}
  2169. }
  2170. )
  2171. data = {
  2172. 'repo': 'test',
  2173. }
  2174. # Valid request
  2175. output = self.app.post(
  2176. '/api/0/fork/', data=data, headers=headers)
  2177. self.assertEqual(output.status_code, 200)
  2178. data = json.loads(output.data)
  2179. self.assertDictEqual(
  2180. data,
  2181. {
  2182. "message": "Repo \"test\" cloned to \"pingou/test\""
  2183. }
  2184. )
  2185. data = {
  2186. 'repo': 'test',
  2187. }
  2188. # project already forked
  2189. output = self.app.post(
  2190. '/api/0/fork/', data=data, headers=headers)
  2191. self.assertEqual(output.status_code, 400)
  2192. data = json.loads(output.data)
  2193. self.assertDictEqual(
  2194. data,
  2195. {
  2196. "error": "Repo \"forks/pingou/test\" already exists",
  2197. "error_code": "ENOCODE"
  2198. }
  2199. )
  2200. data = {
  2201. 'repo': 'test',
  2202. 'username': 'pingou',
  2203. }
  2204. # Fork already exists
  2205. output = self.app.post(
  2206. '/api/0/fork/', data=data, headers=headers)
  2207. self.assertEqual(output.status_code, 400)
  2208. data = json.loads(output.data)
  2209. self.assertDictEqual(
  2210. data,
  2211. {
  2212. "error": "Repo \"forks/pingou/test\" already exists",
  2213. "error_code": "ENOCODE"
  2214. }
  2215. )
  2216. data = {
  2217. 'repo': 'test',
  2218. 'namespace': 'pingou',
  2219. }
  2220. # Repo does not exists
  2221. output = self.app.post(
  2222. '/api/0/fork/', data=data, headers=headers)
  2223. self.assertEqual(output.status_code, 404)
  2224. data = json.loads(output.data)
  2225. self.assertDictEqual(
  2226. data,
  2227. {
  2228. "error": "Project not found",
  2229. "error_code": "ENOPROJECT"
  2230. }
  2231. )
  2232. def test_api_fork_project_user_token(self):
  2233. """ Test the api_fork_project method of the flask api. """
  2234. tests.create_projects(self.session)
  2235. for folder in ['docs', 'tickets', 'requests', 'repos']:
  2236. tests.create_projects_git(
  2237. os.path.join(self.path, folder), bare=True)
  2238. tests.create_tokens(self.session, project_id=None)
  2239. tests.create_tokens_acl(self.session)
  2240. headers = {'Authorization': 'token foo_token'}
  2241. # Invalid token
  2242. output = self.app.post('/api/0/fork', headers=headers)
  2243. self.assertEqual(output.status_code, 401)
  2244. data = json.loads(output.data)
  2245. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  2246. self.assertEqual(
  2247. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  2248. self.assertEqual(
  2249. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  2250. headers = {'Authorization': 'token aaabbbcccddd'}
  2251. # No input
  2252. output = self.app.post('/api/0/fork', headers=headers)
  2253. self.assertEqual(output.status_code, 400)
  2254. data = json.loads(output.data)
  2255. self.assertDictEqual(
  2256. data,
  2257. {
  2258. "error": "Invalid or incomplete input submitted",
  2259. "error_code": "EINVALIDREQ",
  2260. "errors": {"repo": ["This field is required."]}
  2261. }
  2262. )
  2263. data = {
  2264. 'name': 'test',
  2265. }
  2266. # Incomplete request
  2267. output = self.app.post(
  2268. '/api/0/fork', data=data, headers=headers)
  2269. self.assertEqual(output.status_code, 400)
  2270. data = json.loads(output.data)
  2271. self.assertDictEqual(
  2272. data,
  2273. {
  2274. "error": "Invalid or incomplete input submitted",
  2275. "error_code": "EINVALIDREQ",
  2276. "errors": {"repo": ["This field is required."]}
  2277. }
  2278. )
  2279. data = {
  2280. 'repo': 'test',
  2281. }
  2282. # Valid request
  2283. output = self.app.post(
  2284. '/api/0/fork/', data=data, headers=headers)
  2285. self.assertEqual(output.status_code, 200)
  2286. data = json.loads(output.data)
  2287. self.assertDictEqual(
  2288. data,
  2289. {
  2290. "message": "Repo \"test\" cloned to \"pingou/test\""
  2291. }
  2292. )
  2293. data = {
  2294. 'repo': 'test',
  2295. }
  2296. # project already forked
  2297. output = self.app.post(
  2298. '/api/0/fork/', data=data, headers=headers)
  2299. self.assertEqual(output.status_code, 400)
  2300. data = json.loads(output.data)
  2301. self.assertDictEqual(
  2302. data,
  2303. {
  2304. "error": "Repo \"forks/pingou/test\" already exists",
  2305. "error_code": "ENOCODE"
  2306. }
  2307. )
  2308. data = {
  2309. 'repo': 'test',
  2310. 'username': 'pingou',
  2311. }
  2312. # Fork already exists
  2313. output = self.app.post(
  2314. '/api/0/fork/', data=data, headers=headers)
  2315. self.assertEqual(output.status_code, 400)
  2316. data = json.loads(output.data)
  2317. self.assertDictEqual(
  2318. data,
  2319. {
  2320. "error": "Repo \"forks/pingou/test\" already exists",
  2321. "error_code": "ENOCODE"
  2322. }
  2323. )
  2324. data = {
  2325. 'repo': 'test',
  2326. 'namespace': 'pingou',
  2327. }
  2328. # Repo does not exists
  2329. output = self.app.post(
  2330. '/api/0/fork/', data=data, headers=headers)
  2331. self.assertEqual(output.status_code, 404)
  2332. data = json.loads(output.data)
  2333. self.assertDictEqual(
  2334. data,
  2335. {
  2336. "error": "Project not found",
  2337. "error_code": "ENOPROJECT"
  2338. }
  2339. )
  2340. def test_api_generate_acls(self):
  2341. """ Test the api_generate_acls method of the flask api """
  2342. tests.create_projects(self.session)
  2343. tests.create_tokens(self.session, project_id=None)
  2344. tests.create_tokens_acl(
  2345. self.session, 'aaabbbcccddd', 'generate_acls_project')
  2346. headers = {'Authorization': 'token aaabbbcccddd'}
  2347. user = pagure.lib.get_user(self.session, 'pingou')
  2348. output = self.app.post(
  2349. '/api/0/test/git/generateacls', headers=headers,
  2350. data={'wait': False})
  2351. self.assertEqual(output.status_code, 200)
  2352. data = json.loads(output.get_data(as_text=True))
  2353. expected_output = {
  2354. 'message': 'Project ACL generation queued',
  2355. 'taskid': 'abc-1234'
  2356. }
  2357. self.assertEqual(data, expected_output)
  2358. self.mock_gen_acls.assert_called_once_with(
  2359. name='test', namespace=None, user=None, group=None)
  2360. def test_api_generate_acls_json(self):
  2361. """ Test the api_generate_acls method of the flask api using JSON """
  2362. tests.create_projects(self.session)
  2363. tests.create_tokens(self.session, project_id=None)
  2364. tests.create_tokens_acl(
  2365. self.session, 'aaabbbcccddd', 'generate_acls_project')
  2366. headers = {'Authorization': 'token aaabbbcccddd',
  2367. 'Content-Type': 'application/json'}
  2368. user = pagure.lib.get_user(self.session, 'pingou')
  2369. output = self.app.post(
  2370. '/api/0/test/git/generateacls', headers=headers,
  2371. data=json.dumps({'wait': False}))
  2372. self.assertEqual(output.status_code, 200)
  2373. data = json.loads(output.get_data(as_text=True))
  2374. expected_output = {
  2375. 'message': 'Project ACL generation queued',
  2376. 'taskid': 'abc-1234'
  2377. }
  2378. self.assertEqual(data, expected_output)
  2379. self.mock_gen_acls.assert_called_once_with(
  2380. name='test', namespace=None, user=None, group=None)
  2381. def test_api_generate_acls_wait_true(self):
  2382. """ Test the api_generate_acls method of the flask api when wait is
  2383. set to True """
  2384. tests.create_projects(self.session)
  2385. tests.create_tokens(self.session, project_id=None)
  2386. tests.create_tokens_acl(
  2387. self.session, 'aaabbbcccddd', 'generate_acls_project')
  2388. headers = {'Authorization': 'token aaabbbcccddd'}
  2389. task_result = Mock()
  2390. task_result.id = 'abc-1234'
  2391. self.mock_gen_acls.return_value = task_result
  2392. user = pagure.lib.get_user(self.session, 'pingou')
  2393. output = self.app.post(
  2394. '/api/0/test/git/generateacls', headers=headers,
  2395. data={'wait': True})
  2396. self.assertEqual(output.status_code, 200)
  2397. data = json.loads(output.get_data(as_text=True))
  2398. expected_output = {
  2399. 'message': 'Project ACLs generated',
  2400. }
  2401. self.assertEqual(data, expected_output)
  2402. self.mock_gen_acls.assert_called_once_with(
  2403. name='test', namespace=None, user=None, group=None)
  2404. self.assertTrue(task_result.get.called)
  2405. def test_api_generate_acls_no_project(self):
  2406. """ Test the api_generate_acls method of the flask api when the project
  2407. doesn't exist """
  2408. tests.create_projects(self.session)
  2409. tests.create_tokens(self.session, project_id=None)
  2410. tests.create_tokens_acl(
  2411. self.session, 'aaabbbcccddd', 'generate_acls_project')
  2412. headers = {'Authorization': 'token aaabbbcccddd'}
  2413. user = pagure.lib.get_user(self.session, 'pingou')
  2414. output = self.app.post(
  2415. '/api/0/test12345123/git/generateacls', headers=headers,
  2416. data={'wait': False})
  2417. self.assertEqual(output.status_code, 404)
  2418. data = json.loads(output.get_data(as_text=True))
  2419. expected_output = {
  2420. 'error_code': 'ENOPROJECT',
  2421. 'error': 'Project not found'
  2422. }
  2423. self.assertEqual(data, expected_output)
  2424. def test_api_new_git_branch(self):
  2425. """ Test the api_new_branch method of the flask api """
  2426. tests.create_projects(self.session)
  2427. repo_path = os.path.join(self.path, 'repos')
  2428. tests.create_projects_git(repo_path, bare=True)
  2429. tests.add_content_git_repo(os.path.join(repo_path, 'test.git'))
  2430. tests.create_tokens(self.session, project_id=None)
  2431. tests.create_tokens_acl(
  2432. self.session, 'aaabbbcccddd', 'create_branch')
  2433. headers = {'Authorization': 'token aaabbbcccddd'}
  2434. args = {'branch': 'test123'}
  2435. output = self.app.post('/api/0/test/git/branch', headers=headers,
  2436. data=args)
  2437. self.assertEqual(output.status_code, 200)
  2438. data = json.loads(output.data)
  2439. expected_output = {
  2440. 'message': 'Project branch was created',
  2441. }
  2442. self.assertEqual(data, expected_output)
  2443. git_path = os.path.join(self.path, 'repos', 'test.git')
  2444. repo_obj = pygit2.Repository(git_path)
  2445. self.assertIn('test123', repo_obj.listall_branches())
  2446. def test_api_new_git_branch_json(self):
  2447. """ Test the api_new_branch method of the flask api """
  2448. tests.create_projects(self.session)
  2449. repo_path = os.path.join(self.path, 'repos')
  2450. tests.create_projects_git(repo_path, bare=True)
  2451. tests.add_content_git_repo(os.path.join(repo_path, 'test.git'))
  2452. tests.create_tokens(self.session, project_id=None)
  2453. tests.create_tokens_acl(
  2454. self.session, 'aaabbbcccddd', 'create_branch')
  2455. headers = {'Authorization': 'token aaabbbcccddd',
  2456. 'Content-Type': 'application/json'}
  2457. args = {'branch': 'test123'}
  2458. output = self.app.post('/api/0/test/git/branch', headers=headers,
  2459. data=json.dumps(args))
  2460. self.assertEqual(output.status_code, 200)
  2461. data = json.loads(output.data)
  2462. expected_output = {
  2463. 'message': 'Project branch was created',
  2464. }
  2465. self.assertEqual(data, expected_output)
  2466. git_path = os.path.join(self.path, 'repos', 'test.git')
  2467. repo_obj = pygit2.Repository(git_path)
  2468. self.assertIn('test123', repo_obj.listall_branches())
  2469. def test_api_new_git_branch_from_branch(self):
  2470. """ Test the api_new_branch method of the flask api """
  2471. tests.create_projects(self.session)
  2472. repo_path = os.path.join(self.path, 'repos')
  2473. tests.create_projects_git(repo_path, bare=True)
  2474. tests.add_content_git_repo(os.path.join(repo_path, 'test.git'))
  2475. tests.create_tokens(self.session, project_id=None)
  2476. tests.create_tokens_acl(
  2477. self.session, 'aaabbbcccddd', 'create_branch')
  2478. git_path = os.path.join(self.path, 'repos', 'test.git')
  2479. repo_obj = pygit2.Repository(git_path)
  2480. parent = pagure.lib.git.get_branch_ref(repo_obj, 'master').get_object()
  2481. repo_obj.create_branch('dev123', parent)
  2482. headers = {'Authorization': 'token aaabbbcccddd'}
  2483. args = {'branch': 'test123', 'from_branch': 'dev123'}
  2484. output = self.app.post('/api/0/test/git/branch', headers=headers,
  2485. data=args)
  2486. self.assertEqual(output.status_code, 200)
  2487. data = json.loads(output.data)
  2488. expected_output = {
  2489. 'message': 'Project branch was created',
  2490. }
  2491. self.assertEqual(data, expected_output)
  2492. self.assertIn('test123', repo_obj.listall_branches())
  2493. def test_api_new_git_branch_already_exists(self):
  2494. """ Test the api_new_branch method of the flask api when branch already
  2495. exists """
  2496. tests.create_projects(self.session)
  2497. repo_path = os.path.join(self.path, 'repos')
  2498. tests.create_projects_git(repo_path, bare=True)
  2499. tests.add_content_git_repo(os.path.join(repo_path, 'test.git'))
  2500. tests.create_tokens(self.session, project_id=None)
  2501. tests.create_tokens_acl(
  2502. self.session, 'aaabbbcccddd', 'create_branch')
  2503. headers = {'Authorization': 'token aaabbbcccddd'}
  2504. args = {'branch': 'master'}
  2505. output = self.app.post('/api/0/test/git/branch', headers=headers,
  2506. data=args)
  2507. self.assertEqual(output.status_code, 400)
  2508. data = json.loads(output.data)
  2509. expected_output = {
  2510. 'error': 'The branch "master" already exists',
  2511. 'error_code': 'ENOCODE'
  2512. }
  2513. self.assertEqual(data, expected_output)
  2514. def test_api_new_git_branch_from_commit(self):
  2515. """ Test the api_new_branch method of the flask api """
  2516. tests.create_projects(self.session)
  2517. repos_path = os.path.join(self.path, 'repos')
  2518. tests.create_projects_git(repos_path, bare=True)
  2519. git_path = os.path.join(repos_path, 'test.git')
  2520. tests.add_content_git_repo(git_path)
  2521. tests.create_tokens(self.session, project_id=None)
  2522. tests.create_tokens_acl(
  2523. self.session, 'aaabbbcccddd', 'create_branch')
  2524. repo_obj = pygit2.Repository(git_path)
  2525. from_commit = repo_obj.revparse_single('HEAD').oid.hex
  2526. headers = {'Authorization': 'token aaabbbcccddd'}
  2527. args = {'branch': 'test123', 'from_commit': from_commit}
  2528. output = self.app.post('/api/0/test/git/branch', headers=headers,
  2529. data=args)
  2530. self.assertEqual(output.status_code, 200)
  2531. data = json.loads(output.data)
  2532. expected_output = {
  2533. 'message': 'Project branch was created',
  2534. }
  2535. self.assertEqual(data, expected_output)
  2536. self.assertIn('test123', repo_obj.listall_branches())
  2537. class PagureFlaskApiProjectFlagtests(tests.Modeltests):
  2538. """ Tests for the flask API of pagure for flagging commit in project
  2539. """
  2540. def setUp(self):
  2541. """ Set up the environnment, ran before every tests. """
  2542. super(PagureFlaskApiProjectFlagtests, self).setUp()
  2543. tests.create_projects(self.session)
  2544. repo_path = os.path.join(self.path, 'repos')
  2545. self.git_path = os.path.join(repo_path, 'test.git')
  2546. tests.create_projects_git(repo_path, bare=True)
  2547. tests.add_content_git_repo(self.git_path)
  2548. tests.create_tokens(self.session, project_id=None)
  2549. tests.create_tokens_acl(
  2550. self.session, 'aaabbbcccddd', 'commit_flag')
  2551. def test_flag_commit_missing_status(self):
  2552. """ Test flagging a commit with missing precentage. """
  2553. repo_obj = pygit2.Repository(self.git_path)
  2554. commit = repo_obj.revparse_single('HEAD')
  2555. headers = {'Authorization': 'token aaabbbcccddd'}
  2556. data = {
  2557. 'username': 'Jenkins',
  2558. 'comment': 'Tests passed',
  2559. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2560. 'uid': 'jenkins_build_pagure_100+seed',
  2561. }
  2562. output = self.app.post(
  2563. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2564. headers=headers, data=data)
  2565. self.assertEqual(output.status_code, 400)
  2566. data = json.loads(output.data)
  2567. expected_output = {
  2568. "error": "Invalid or incomplete input submitted",
  2569. "error_code": "EINVALIDREQ",
  2570. "errors": {
  2571. "status": [
  2572. "Not a valid choice"
  2573. ]
  2574. }
  2575. }
  2576. self.assertEqual(data, expected_output)
  2577. def test_flag_commit_missing_username(self):
  2578. """ Test flagging a commit with missing username. """
  2579. repo_obj = pygit2.Repository(self.git_path)
  2580. commit = repo_obj.revparse_single('HEAD')
  2581. headers = {'Authorization': 'token aaabbbcccddd'}
  2582. data = {
  2583. 'percent': 100,
  2584. 'comment': 'Tests passed',
  2585. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2586. 'uid': 'jenkins_build_pagure_100+seed',
  2587. 'status': 'success',
  2588. }
  2589. output = self.app.post(
  2590. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2591. headers=headers, data=data)
  2592. self.assertEqual(output.status_code, 400)
  2593. data = json.loads(output.data)
  2594. expected_output = {
  2595. "error": "Invalid or incomplete input submitted",
  2596. "error_code": "EINVALIDREQ",
  2597. "errors": {
  2598. "username": [
  2599. "This field is required."
  2600. ]
  2601. }
  2602. }
  2603. self.assertEqual(data, expected_output)
  2604. def test_flag_commit_missing_comment(self):
  2605. """ Test flagging a commit with missing comment. """
  2606. repo_obj = pygit2.Repository(self.git_path)
  2607. commit = repo_obj.revparse_single('HEAD')
  2608. headers = {'Authorization': 'token aaabbbcccddd'}
  2609. data = {
  2610. 'username': 'Jenkins',
  2611. 'percent': 100,
  2612. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2613. 'uid': 'jenkins_build_pagure_100+seed',
  2614. 'status': 'success',
  2615. }
  2616. output = self.app.post(
  2617. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2618. headers=headers, data=data)
  2619. self.assertEqual(output.status_code, 400)
  2620. data = json.loads(output.data)
  2621. expected_output = {
  2622. "error": "Invalid or incomplete input submitted",
  2623. "error_code": "EINVALIDREQ",
  2624. "errors": {
  2625. "comment": [
  2626. "This field is required."
  2627. ]
  2628. }
  2629. }
  2630. self.assertEqual(data, expected_output)
  2631. def test_flag_commit_missing_url(self):
  2632. """ Test flagging a commit with missing url. """
  2633. repo_obj = pygit2.Repository(self.git_path)
  2634. commit = repo_obj.revparse_single('HEAD')
  2635. headers = {'Authorization': 'token aaabbbcccddd'}
  2636. data = {
  2637. 'username': 'Jenkins',
  2638. 'percent': 100,
  2639. 'comment': 'Tests passed',
  2640. 'uid': 'jenkins_build_pagure_100+seed',
  2641. 'status': 'success',
  2642. }
  2643. output = self.app.post(
  2644. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2645. headers=headers, data=data)
  2646. self.assertEqual(output.status_code, 400)
  2647. data = json.loads(output.data)
  2648. expected_output = {
  2649. "error": "Invalid or incomplete input submitted",
  2650. "error_code": "EINVALIDREQ",
  2651. "errors": {
  2652. "url": [
  2653. "This field is required."
  2654. ]
  2655. }
  2656. }
  2657. self.assertEqual(data, expected_output)
  2658. def test_flag_commit_invalid_token(self):
  2659. """ Test flagging a commit with missing info. """
  2660. repo_obj = pygit2.Repository(self.git_path)
  2661. commit = repo_obj.revparse_single('HEAD')
  2662. headers = {'Authorization': 'token 123'}
  2663. data = {
  2664. 'username': 'Jenkins',
  2665. 'percent': 100,
  2666. 'comment': 'Tests passed',
  2667. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2668. 'uid': 'jenkins_build_pagure_100+seed',
  2669. }
  2670. output = self.app.post(
  2671. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2672. headers=headers, data=data)
  2673. self.assertEqual(output.status_code, 401)
  2674. data = json.loads(output.data)
  2675. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  2676. self.assertEqual(
  2677. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  2678. self.assertEqual(
  2679. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  2680. def test_flag_commit_invalid_status(self):
  2681. """ Test flagging a commit with an invalid status. """
  2682. repo_obj = pygit2.Repository(self.git_path)
  2683. commit = repo_obj.revparse_single('HEAD')
  2684. headers = {'Authorization': 'token aaabbbcccddd'}
  2685. data = {
  2686. 'username': 'Jenkins',
  2687. 'percent': 100,
  2688. 'comment': 'Tests passed',
  2689. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2690. 'status': 'foobar',
  2691. }
  2692. output = self.app.post(
  2693. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2694. headers=headers, data=data)
  2695. self.assertEqual(output.status_code, 400)
  2696. data = json.loads(output.data)
  2697. self.assertEqual(
  2698. data,
  2699. {
  2700. u'errors': {u'status': [u'Not a valid choice']},
  2701. u'error_code': u'EINVALIDREQ',
  2702. u'error': u'Invalid or incomplete input submitted'
  2703. }
  2704. )
  2705. def test_flag_commit_with_uid(self):
  2706. """ Test flagging a commit with provided uid. """
  2707. repo_obj = pygit2.Repository(self.git_path)
  2708. commit = repo_obj.revparse_single('HEAD')
  2709. headers = {'Authorization': 'token aaabbbcccddd'}
  2710. data = {
  2711. 'username': 'Jenkins',
  2712. 'percent': 100,
  2713. 'comment': 'Tests passed',
  2714. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2715. 'uid': 'jenkins_build_pagure_100+seed',
  2716. 'status': 'success',
  2717. }
  2718. output = self.app.post(
  2719. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2720. headers=headers, data=data)
  2721. self.assertEqual(output.status_code, 200)
  2722. data = json.loads(output.data)
  2723. data['flag']['date_created'] = u'1510742565'
  2724. data['flag']['commit_hash'] = u'62b49f00d489452994de5010565fab81'
  2725. expected_output = {
  2726. u'flag': {
  2727. u'comment': u'Tests passed',
  2728. u'commit_hash': u'62b49f00d489452994de5010565fab81',
  2729. u'date_created': u'1510742565',
  2730. u'percent': 100,
  2731. u'status': 'success',
  2732. u'url': u'http://jenkins.cloud.fedoraproject.org/',
  2733. u'user': {
  2734. u'default_email': u'bar@pingou.com',
  2735. u'emails': [u'bar@pingou.com', u'foo@pingou.com'],
  2736. u'fullname': u'PY C',
  2737. u'name': u'pingou'},
  2738. u'username': u'Jenkins'
  2739. },
  2740. u'message': u'Flag added',
  2741. u'uid': u'jenkins_build_pagure_100+seed'
  2742. }
  2743. self.assertEqual(data, expected_output)
  2744. @patch('pagure.lib.notify.send_email')
  2745. def test_flag_commit_without_uid(self, mock_email):
  2746. """ Test flagging a commit with missing info.
  2747. Also ensure notifications aren't sent when they are not asked for.
  2748. """
  2749. repo_obj = pygit2.Repository(self.git_path)
  2750. commit = repo_obj.revparse_single('HEAD')
  2751. headers = {'Authorization': 'token aaabbbcccddd'}
  2752. data = {
  2753. 'username': 'Jenkins',
  2754. 'percent': 100,
  2755. 'comment': 'Tests passed',
  2756. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2757. 'status': 'success',
  2758. }
  2759. output = self.app.post(
  2760. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2761. headers=headers, data=data)
  2762. self.assertEqual(output.status_code, 200)
  2763. data = json.loads(output.data)
  2764. self.assertNotEqual(
  2765. data['uid'],
  2766. u'jenkins_build_pagure_100+seed'
  2767. )
  2768. data['flag']['date_created'] = u'1510742565'
  2769. data['uid'] = 'b1de8f80defd4a81afe2e09f39678087'
  2770. expected_output = {
  2771. u'flag': {
  2772. u'comment': u'Tests passed',
  2773. u'commit_hash': commit.oid.hex,
  2774. u'date_created': u'1510742565',
  2775. u'percent': 100,
  2776. u'status': 'success',
  2777. u'url': u'http://jenkins.cloud.fedoraproject.org/',
  2778. u'user': {
  2779. u'default_email': u'bar@pingou.com',
  2780. u'emails': [u'bar@pingou.com', u'foo@pingou.com'],
  2781. u'fullname': u'PY C',
  2782. u'name': u'pingou'},
  2783. u'username': u'Jenkins'
  2784. },
  2785. u'message': u'Flag added',
  2786. u'uid': u'b1de8f80defd4a81afe2e09f39678087'
  2787. }
  2788. self.assertEqual(data, expected_output)
  2789. mock_email.assert_not_called()
  2790. @patch('pagure.lib.notify.send_email')
  2791. def test_flag_commit_with_notification(self, mock_email):
  2792. """ Test flagging a commit with notification enabled. """
  2793. # Enable commit notifications
  2794. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2795. settings = repo.settings
  2796. settings['notify_on_commit_flag'] = True
  2797. repo.settings = settings
  2798. self.session.add(repo)
  2799. self.session.commit()
  2800. repo_obj = pygit2.Repository(self.git_path)
  2801. commit = repo_obj.revparse_single('HEAD')
  2802. headers = {'Authorization': 'token aaabbbcccddd'}
  2803. data = {
  2804. 'username': 'Jenkins',
  2805. 'percent': 100,
  2806. 'comment': 'Tests passed',
  2807. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2808. 'status': 'success',
  2809. }
  2810. output = self.app.post(
  2811. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2812. headers=headers, data=data)
  2813. self.assertEqual(output.status_code, 200)
  2814. data = json.loads(output.data)
  2815. self.assertNotEqual(
  2816. data['uid'],
  2817. u'jenkins_build_pagure_100+seed'
  2818. )
  2819. data['flag']['date_created'] = u'1510742565'
  2820. data['uid'] = 'b1de8f80defd4a81afe2e09f39678087'
  2821. expected_output = {
  2822. u'flag': {
  2823. u'comment': u'Tests passed',
  2824. u'commit_hash': commit.oid.hex,
  2825. u'date_created': u'1510742565',
  2826. u'percent': 100,
  2827. u'status': 'success',
  2828. u'url': u'http://jenkins.cloud.fedoraproject.org/',
  2829. u'user': {
  2830. u'default_email': u'bar@pingou.com',
  2831. u'emails': [u'bar@pingou.com', u'foo@pingou.com'],
  2832. u'fullname': u'PY C',
  2833. u'name': u'pingou'},
  2834. u'username': u'Jenkins'
  2835. },
  2836. u'message': u'Flag added',
  2837. u'uid': u'b1de8f80defd4a81afe2e09f39678087'
  2838. }
  2839. self.assertEqual(data, expected_output)
  2840. mock_email.assert_called_once_with(
  2841. u'\nJenkins flagged the commit '
  2842. u'`' + commit.oid.hex + u'` as success: '
  2843. u'Tests passed\n\n'
  2844. u'https://pagure.org/test/c/' + commit.oid.hex + u'\n',
  2845. u'Coommit #' + commit.oid.hex + u' - Jenkins: success',
  2846. u'bar@pingou.com',
  2847. in_reply_to=u'test-project-1',
  2848. mail_id=u'test-commit-1-1',
  2849. project_name=u'test',
  2850. user_from=u'Jenkins'
  2851. )
  2852. @patch.dict('pagure.config.config',
  2853. {
  2854. 'FLAG_STATUSES_LABELS':
  2855. {
  2856. 'pend!': 'label-info',
  2857. 'succeed!': 'label-success',
  2858. 'fail!': 'label-danger',
  2859. 'what?': 'label-warning',
  2860. },
  2861. 'FLAG_PENDING': 'pend!',
  2862. 'FLAG_SUCCESS': 'succeed!',
  2863. 'FLAG_FAILURE': 'fail!',
  2864. })
  2865. def test_flag_commit_with_custom_flags(self):
  2866. """ Test flagging when custom flags are set up
  2867. """
  2868. repo_obj = pygit2.Repository(self.git_path)
  2869. commit = repo_obj.revparse_single('HEAD')
  2870. headers = {'Authorization': 'token aaabbbcccddd'}
  2871. send_data = {
  2872. 'username': 'Jenkins',
  2873. 'percent': 100,
  2874. 'comment': 'Tests passed',
  2875. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  2876. 'status': 'succeed!',
  2877. }
  2878. output = self.app.post(
  2879. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2880. headers=headers, data=send_data)
  2881. self.assertEqual(output.status_code, 200)
  2882. data = json.loads(output.data)
  2883. self.assertEqual(data['flag']['status'], 'succeed!')
  2884. # Try invalid flag status
  2885. send_data['status'] = 'nooooo....'
  2886. output = self.app.post(
  2887. '/api/0/test/c/%s/flag' % commit.oid.hex,
  2888. headers=headers, data=send_data)
  2889. self.assertEqual(output.status_code, 400)
  2890. data = json.loads(output.data)
  2891. self.assertEqual(
  2892. data,
  2893. {
  2894. u'errors': {u'status': [u'Not a valid choice']},
  2895. u'error_code': u'EINVALIDREQ',
  2896. u'error': u'Invalid or incomplete input submitted'
  2897. }
  2898. )
  2899. def test_commit_flags(self):
  2900. """ Test retrieving commit flags. """
  2901. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2902. repo_obj = pygit2.Repository(self.git_path)
  2903. commit = repo_obj.revparse_single('HEAD')
  2904. # test with no flags
  2905. output = self.app.get('/api/0/test/c/%s/flag' % commit.oid.hex)
  2906. self.assertEqual(json.loads(output.data), {'total_flags': 0, 'flags': []})
  2907. self.assertEqual(output.status_code, 200)
  2908. # add some flags and retrieve them
  2909. pagure.lib.add_commit_flag(
  2910. session=self.session,
  2911. repo=repo,
  2912. commit_hash=commit.oid.hex,
  2913. username='simple-koji-ci',
  2914. status='pending',
  2915. percent=None,
  2916. comment='Build is running',
  2917. url='https://koji.fp.o/koji...',
  2918. uid='uid',
  2919. user='foo',
  2920. token='aaabbbcccddd'
  2921. )
  2922. pagure.lib.add_commit_flag(
  2923. session=self.session,
  2924. repo=repo,
  2925. commit_hash=commit.oid.hex,
  2926. username='complex-koji-ci',
  2927. status='success',
  2928. percent=None,
  2929. comment='Build succeeded',
  2930. url='https://koji.fp.o/koji...',
  2931. uid='uid2',
  2932. user='foo',
  2933. token='aaabbbcccddd'
  2934. )
  2935. self.session.commit()
  2936. output = self.app.get('/api/0/test/c/%s/flag' % commit.oid.hex)
  2937. data = json.loads(output.data)
  2938. for f in data['flags']:
  2939. f['date_created'] = u'1510742565'
  2940. f['commit_hash'] = u'62b49f00d489452994de5010565fab81'
  2941. expected_output = {
  2942. u"flags": [
  2943. {
  2944. u"comment": u"Build is running",
  2945. u"commit_hash": u"62b49f00d489452994de5010565fab81",
  2946. u"date_created": u"1510742565",
  2947. u"percent": None,
  2948. u"status": u"pending",
  2949. u"url": u"https://koji.fp.o/koji...",
  2950. u"user": {
  2951. u"fullname": u"foo bar",
  2952. u"name": u"foo"
  2953. },
  2954. u"username": u"simple-koji-ci"
  2955. },
  2956. {
  2957. u"comment": u"Build succeeded",
  2958. u"commit_hash": u"62b49f00d489452994de5010565fab81",
  2959. u"date_created": u"1510742565",
  2960. u"percent": None,
  2961. u"status": u"success",
  2962. u"url": u"https://koji.fp.o/koji...",
  2963. u"user": {
  2964. u"fullname": u"foo bar",
  2965. u"name": u"foo"
  2966. },
  2967. u"username": u"complex-koji-ci"
  2968. }
  2969. ],
  2970. u"total_flags": 2
  2971. }
  2972. self.assertEqual(data, expected_output)
  2973. if __name__ == '__main__':
  2974. unittest.main(verbosity=2)