test_pagure_flask_api_project.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015-2016 - 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 datetime
  10. import json
  11. import unittest
  12. import shutil
  13. import sys
  14. import tempfile
  15. import os
  16. import pygit2
  17. from mock import patch
  18. sys.path.insert(0, os.path.join(os.path.dirname(
  19. os.path.abspath(__file__)), '..'))
  20. import pagure.lib
  21. import tests
  22. from pagure.lib.repo import PagureRepo
  23. class PagureFlaskApiProjecttests(tests.Modeltests):
  24. """ Tests for the flask API of pagure for issue """
  25. def setUp(self):
  26. """ Set up the environnment, ran before every tests. """
  27. super(PagureFlaskApiProjecttests, self).setUp()
  28. pagure.APP.config['TESTING'] = True
  29. pagure.SESSION = self.session
  30. pagure.api.SESSION = self.session
  31. pagure.api.project.SESSION = self.session
  32. pagure.lib.SESSION = self.session
  33. pagure.APP.config['GIT_FOLDER'] = os.path.join(self.path, 'repos')
  34. pagure.APP.config['FORK_FOLDER'] = os.path.join(
  35. self.path, 'forks')
  36. pagure.APP.config['REQUESTS_FOLDER'] = os.path.join(
  37. self.path, 'requests')
  38. pagure.APP.config['TICKETS_FOLDER'] = os.path.join(
  39. self.path, 'tickets')
  40. pagure.APP.config['DOCS_FOLDER'] = os.path.join(
  41. self.path, 'docs')
  42. self.app = pagure.APP.test_client()
  43. def test_api_git_tags(self):
  44. """ Test the api_git_tags method of the flask api. """
  45. tests.create_projects(self.session)
  46. # Create a git repo to play with
  47. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  48. repo = pygit2.init_repository(gitrepo, bare=True)
  49. newpath = tempfile.mkdtemp(prefix='pagure-fork-test')
  50. repopath = os.path.join(newpath, 'test')
  51. clone_repo = pygit2.clone_repository(gitrepo, repopath)
  52. # Create a file in that git repo
  53. with open(os.path.join(repopath, 'sources'), 'w') as stream:
  54. stream.write('foo\n bar')
  55. clone_repo.index.add('sources')
  56. clone_repo.index.write()
  57. # Commits the files added
  58. tree = clone_repo.index.write_tree()
  59. author = pygit2.Signature(
  60. 'Alice Author', 'alice@authors.tld')
  61. committer = pygit2.Signature(
  62. 'Cecil Committer', 'cecil@committers.tld')
  63. clone_repo.create_commit(
  64. 'refs/heads/master', # the name of the reference to update
  65. author,
  66. committer,
  67. 'Add sources file for testing',
  68. # binary string representing the tree object ID
  69. tree,
  70. # list of binary strings representing parents of the new commit
  71. []
  72. )
  73. refname = 'refs/heads/master:refs/heads/master'
  74. ori_remote = clone_repo.remotes[0]
  75. PagureRepo.push(ori_remote, refname)
  76. # Tag our first commit
  77. first_commit = repo.revparse_single('HEAD')
  78. tagger = pygit2.Signature('Alice Doe', 'adoe@example.com', 12347, 0)
  79. repo.create_tag(
  80. "0.0.1", first_commit.oid.hex, pygit2.GIT_OBJ_COMMIT, tagger,
  81. "Release 0.0.1")
  82. # Check tags
  83. output = self.app.get('/api/0/test/git/tags')
  84. self.assertEqual(output.status_code, 200)
  85. data = json.loads(output.get_data(as_text=True))
  86. self.assertDictEqual(
  87. data,
  88. {'tags': ['0.0.1'], 'total_tags': 1}
  89. )
  90. shutil.rmtree(newpath)
  91. def test_api_projects(self):
  92. """ Test the api_projects method of the flask api. """
  93. tests.create_projects(self.session)
  94. # Check before adding
  95. repo = pagure.lib.get_project(self.session, 'test')
  96. self.assertEqual(repo.tags, [])
  97. # Adding a tag
  98. output = pagure.lib.update_tags(
  99. self.session, repo, 'infra', 'pingou',
  100. ticketfolder=None)
  101. self.assertEqual(output, ['Tag added: infra'])
  102. # Check after adding
  103. repo = pagure.lib.get_project(self.session, 'test')
  104. self.assertEqual(len(repo.tags), 1)
  105. self.assertEqual(repo.tags_text, ['infra'])
  106. # Check the API
  107. output = self.app.get('/api/0/projects?tags=inf')
  108. self.assertEqual(output.status_code, 404)
  109. data = json.loads(output.get_data(as_text=True))
  110. self.assertDictEqual(
  111. data,
  112. {'error_code': 'ENOPROJECTS', 'error': 'No projects found'}
  113. )
  114. output = self.app.get('/api/0/projects?tags=infra')
  115. self.assertEqual(output.status_code, 200)
  116. data = json.loads(output.get_data(as_text=True))
  117. data['projects'][0]['date_created'] = "1436527638"
  118. self.assertDictEqual(
  119. data,
  120. {
  121. "total_projects": 1,
  122. "projects": [
  123. {
  124. "date_created": "1436527638",
  125. "description": "test project #1",
  126. "id": 1,
  127. "name": "test",
  128. "namespace": None,
  129. "parent": None,
  130. "priorities": {},
  131. "tags": ["infra"],
  132. "user": {
  133. "fullname": "PY C",
  134. "name": "pingou"
  135. }
  136. }
  137. ]
  138. }
  139. )
  140. output = self.app.get('/api/0/projects?username=pingou')
  141. self.assertEqual(output.status_code, 200)
  142. data = json.loads(output.get_data(as_text=True))
  143. data['projects'][0]['date_created'] = "1436527638"
  144. data['projects'][1]['date_created'] = "1436527638"
  145. self.assertDictEqual(
  146. data,
  147. {
  148. "total_projects": 2,
  149. "projects": [
  150. {
  151. "date_created": "1436527638",
  152. "description": "test project #1",
  153. "id": 1,
  154. "name": "test",
  155. "namespace": None,
  156. "parent": None,
  157. "priorities": {},
  158. "tags": ["infra"],
  159. "user": {
  160. "fullname": "PY C",
  161. "name": "pingou"
  162. }
  163. },
  164. {
  165. "date_created": "1436527638",
  166. "description": "test project #2",
  167. "id": 2,
  168. "name": "test2",
  169. "namespace": None,
  170. "parent": None,
  171. "priorities": {},
  172. "tags": [],
  173. "user": {
  174. "fullname": "PY C",
  175. "name": "pingou"
  176. }
  177. }
  178. ]
  179. }
  180. )
  181. output = self.app.get('/api/0/projects?username=pingou&tags=infra')
  182. self.assertEqual(output.status_code, 200)
  183. data = json.loads(output.get_data(as_text=True))
  184. data['projects'][0]['date_created'] = "1436527638"
  185. self.assertDictEqual(
  186. data,
  187. {
  188. "total_projects": 1,
  189. "projects": [
  190. {
  191. "date_created": "1436527638",
  192. "description": "test project #1",
  193. "id": 1,
  194. "name": "test",
  195. "namespace": None,
  196. "parent": None,
  197. "priorities": {},
  198. "tags": ["infra"],
  199. "user": {
  200. "fullname": "PY C",
  201. "name": "pingou"
  202. }
  203. }
  204. ]
  205. }
  206. )
  207. @patch('pagure.lib.git.generate_gitolite_acls')
  208. def test_api_new_project(self, p_gga):
  209. """ Test the api_new_project method of the flask api. """
  210. p_gga.return_value = True
  211. tests.create_projects(self.session)
  212. tests.create_projects_git(os.path.join(self.path, 'tickets'))
  213. tests.create_tokens(self.session)
  214. tests.create_tokens_acl(self.session)
  215. headers = {'Authorization': 'token foo_token'}
  216. # Invalid token
  217. output = self.app.post('/api/0/new', headers=headers)
  218. self.assertEqual(output.status_code, 401)
  219. data = json.loads(output.get_data(as_text=True))
  220. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  221. data['error_code'])
  222. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  223. headers = {'Authorization': 'token aaabbbcccddd'}
  224. # No input
  225. output = self.app.post('/api/0/new', headers=headers)
  226. self.assertEqual(output.status_code, 400)
  227. data = json.loads(output.get_data(as_text=True))
  228. self.assertDictEqual(
  229. data,
  230. {
  231. "error": "Invalid or incomplete input submited",
  232. "error_code": "EINVALIDREQ",
  233. }
  234. )
  235. data = {
  236. 'name': 'test',
  237. }
  238. # Incomplete request
  239. output = self.app.post(
  240. '/api/0/new', data=data, headers=headers)
  241. self.assertEqual(output.status_code, 400)
  242. data = json.loads(output.get_data(as_text=True))
  243. self.assertDictEqual(
  244. data,
  245. {
  246. "error": "Invalid or incomplete input submited",
  247. "error_code": "EINVALIDREQ",
  248. }
  249. )
  250. data = {
  251. 'name': 'test',
  252. 'description': 'Just a small test project',
  253. }
  254. # Valid request but repo already exists
  255. output = self.app.post(
  256. '/api/0/new/', data=data, headers=headers)
  257. self.assertEqual(output.status_code, 400)
  258. data = json.loads(output.get_data(as_text=True))
  259. self.assertDictEqual(
  260. data,
  261. {
  262. "error": "The tickets repo \"test.git\" already exists",
  263. "error_code": "ENOCODE"
  264. }
  265. )
  266. data = {
  267. 'name': 'test_42',
  268. 'description': 'Just another small test project',
  269. }
  270. # Valid request
  271. output = self.app.post(
  272. '/api/0/new/', data=data, headers=headers)
  273. self.assertEqual(output.status_code, 200)
  274. data = json.loads(output.get_data(as_text=True))
  275. self.assertDictEqual(
  276. data,
  277. {'message': 'Project "test_42" created'}
  278. )
  279. @patch('pagure.lib.git.generate_gitolite_acls')
  280. def test_api_fork_project(self, p_gga):
  281. """ Test the api_fork_project method of the flask api. """
  282. p_gga.return_value = True
  283. tests.create_projects(self.session)
  284. for folder in ['docs', 'tickets', 'requests', 'repos']:
  285. tests.create_projects_git(
  286. os.path.join(self.path, folder), bare=True)
  287. tests.create_tokens(self.session)
  288. tests.create_tokens_acl(self.session)
  289. headers = {'Authorization': 'token foo_token'}
  290. # Invalid token
  291. output = self.app.post('/api/0/fork', headers=headers)
  292. self.assertEqual(output.status_code, 401)
  293. data = json.loads(output.get_data(as_text=True))
  294. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  295. data['error_code'])
  296. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  297. headers = {'Authorization': 'token aaabbbcccddd'}
  298. # No input
  299. output = self.app.post('/api/0/fork', headers=headers)
  300. self.assertEqual(output.status_code, 400)
  301. data = json.loads(output.get_data(as_text=True))
  302. self.assertDictEqual(
  303. data,
  304. {
  305. "error": "Invalid or incomplete input submited",
  306. "error_code": "EINVALIDREQ",
  307. }
  308. )
  309. data = {
  310. 'name': 'test',
  311. }
  312. # Incomplete request
  313. output = self.app.post(
  314. '/api/0/fork', data=data, headers=headers)
  315. self.assertEqual(output.status_code, 400)
  316. data = json.loads(output.get_data(as_text=True))
  317. self.assertDictEqual(
  318. data,
  319. {
  320. "error": "Invalid or incomplete input submited",
  321. "error_code": "EINVALIDREQ",
  322. }
  323. )
  324. data = {
  325. 'repo': 'test',
  326. }
  327. # Valid request
  328. output = self.app.post(
  329. '/api/0/fork/', data=data, headers=headers)
  330. self.assertEqual(output.status_code, 200)
  331. data = json.loads(output.get_data(as_text=True))
  332. self.assertDictEqual(
  333. data,
  334. {
  335. "message": "Repo \"test\" cloned to \"pingou/test\""
  336. }
  337. )
  338. data = {
  339. 'repo': 'test',
  340. }
  341. # project already forked
  342. output = self.app.post(
  343. '/api/0/fork/', data=data, headers=headers)
  344. self.assertEqual(output.status_code, 400)
  345. data = json.loads(output.get_data(as_text=True))
  346. self.assertDictEqual(
  347. data,
  348. {
  349. "error": "Repo \"forks/pingou/test\" already exists",
  350. "error_code": "ENOCODE"
  351. }
  352. )
  353. data = {
  354. 'repo': 'test',
  355. 'username': 'pingou',
  356. }
  357. # Fork already exists
  358. output = self.app.post(
  359. '/api/0/fork/', data=data, headers=headers)
  360. self.assertEqual(output.status_code, 400)
  361. data = json.loads(output.get_data(as_text=True))
  362. self.assertDictEqual(
  363. data,
  364. {
  365. "error": "Repo \"forks/pingou/test\" already exists",
  366. "error_code": "ENOCODE"
  367. }
  368. )
  369. data = {
  370. 'repo': 'test',
  371. 'namespace': 'pingou',
  372. }
  373. # Repo does not exists
  374. output = self.app.post(
  375. '/api/0/fork/', data=data, headers=headers)
  376. self.assertEqual(output.status_code, 404)
  377. data = json.loads(output.get_data(as_text=True))
  378. self.assertDictEqual(
  379. data,
  380. {
  381. "error": "Project not found",
  382. "error_code": "ENOPROJECT"
  383. }
  384. )
  385. if __name__ == '__main__':
  386. SUITE = unittest.TestLoader().loadTestsFromTestCase(
  387. PagureFlaskApiProjecttests)
  388. unittest.TextTestRunner(verbosity=2).run(SUITE)