__init__.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. """
  7. __requires__ = ['SQLAlchemy >= 0.7']
  8. import pkg_resources
  9. import unittest
  10. import shutil
  11. import sys
  12. import tempfile
  13. import os
  14. from datetime import date
  15. from datetime import datetime
  16. from datetime import timedelta
  17. from functools import wraps
  18. import pygit2
  19. from contextlib import contextmanager
  20. from sqlalchemy import create_engine
  21. from sqlalchemy.orm import sessionmaker
  22. from sqlalchemy.orm import scoped_session
  23. sys.path.insert(0, os.path.join(os.path.dirname(
  24. os.path.abspath(__file__)), '..'))
  25. import pagure
  26. import pagure.lib
  27. import pagure.lib.model
  28. from pagure.lib.repo import PagureRepo
  29. DB_PATH = 'sqlite:///:memory:'
  30. FAITOUT_URL = 'http://faitout.cloud.fedoraproject.org/faitout/'
  31. HERE = os.path.join(os.path.dirname(os.path.abspath(__file__)))
  32. if os.environ.get('BUILD_ID'):
  33. try:
  34. import requests
  35. req = requests.get('%s/new' % FAITOUT_URL)
  36. if req.status_code == 200:
  37. DB_PATH = req.text
  38. print 'Using faitout at: %s' % DB_PATH
  39. except:
  40. pass
  41. # Remove the log handlers for the tests
  42. pagure.LOG.handlers = []
  43. @contextmanager
  44. def user_set(APP, user):
  45. """ Set the provided user as fas_user in the provided application."""
  46. # Hack used to remove the before_request function set by
  47. # flask.ext.fas_openid.FAS which otherwise kills our effort to set a
  48. # flask.g.fas_user.
  49. from flask import appcontext_pushed, g
  50. APP.before_request_funcs[None] = []
  51. def handler(sender, **kwargs):
  52. g.fas_user = user
  53. g.fas_session_id = b'123'
  54. with appcontext_pushed.connected_to(handler, APP):
  55. yield
  56. class Modeltests(unittest.TestCase):
  57. """ Model tests. """
  58. def __init__(self, method_name='runTest'):
  59. """ Constructor. """
  60. unittest.TestCase.__init__(self, method_name)
  61. self.session = None
  62. self.path = tempfile.mkdtemp(prefix='pagure-tests')
  63. self.gitrepo = None
  64. self.gitrepos = None
  65. # pylint: disable=C0103
  66. def setUp(self):
  67. """ Set up the environnment, ran before every tests. """
  68. # Clean up eventual git repo left in the present folder.
  69. for filename in os.listdir(HERE):
  70. filename = os.path.join(HERE, filename)
  71. if filename.endswith('.git') and os.path.isdir(filename):
  72. shutil.rmtree(filename)
  73. for folder in ['tickets', 'repos', 'forks', 'docs',
  74. 'requests' ,'releases']:
  75. folder = os.path.join(HERE, folder)
  76. if os.path.exists(folder):
  77. shutil.rmtree(folder)
  78. os.mkdir(folder)
  79. self.session = pagure.lib.model.create_tables(
  80. DB_PATH, acls=pagure.APP.config.get('ACLS', {}))
  81. # Create a couple of users
  82. item = pagure.lib.model.User(
  83. user='pingou',
  84. fullname='PY C',
  85. password='foo',
  86. default_email='bar@pingou.com',
  87. )
  88. self.session.add(item)
  89. item = pagure.lib.model.UserEmail(
  90. user_id=1,
  91. email='bar@pingou.com')
  92. self.session.add(item)
  93. item = pagure.lib.model.UserEmail(
  94. user_id=1,
  95. email='foo@pingou.com')
  96. self.session.add(item)
  97. item = pagure.lib.model.User(
  98. user='foo',
  99. fullname='foo bar',
  100. password='foo',
  101. default_email='foo@bar.com',
  102. )
  103. self.session.add(item)
  104. item = pagure.lib.model.UserEmail(
  105. user_id=2,
  106. email='foo@bar.com')
  107. self.session.add(item)
  108. self.session.commit()
  109. # Prevent unit-tests to send email, globally
  110. pagure.APP.config['EMAIL_SEND'] = False
  111. # pylint: disable=C0103
  112. def tearDown(self):
  113. """ Remove the test.db database if there is one. """
  114. self.session.close()
  115. # Clear temp directory
  116. shutil.rmtree(self.path)
  117. # Clear DB
  118. if os.path.exists(DB_PATH):
  119. os.unlink(DB_PATH)
  120. if DB_PATH.startswith('postgres'):
  121. if 'localhost' in DB_PATH:
  122. pagure.lib.model.drop_tables(DB_PATH, self.session.bind)
  123. else:
  124. db_name = DB_PATH.rsplit('/', 1)[1]
  125. requests.get('%s/clean/%s' % (FAITOUT_URL, db_name))
  126. class FakeGroup(object):
  127. """ Fake object used to make the FakeUser object closer to the
  128. expectations.
  129. """
  130. def __init__(self, name):
  131. """ Constructor.
  132. :arg name: the name given to the name attribute of this object.
  133. """
  134. self.name = name
  135. self.group_type = 'cla'
  136. # pylint: disable=R0903
  137. class FakeUser(object):
  138. """ Fake user used to test the fedocallib library. """
  139. def __init__(self, groups=[], username='username', cla_done=True):
  140. """ Constructor.
  141. :arg groups: list of the groups in which this fake user is
  142. supposed to be.
  143. """
  144. if isinstance(groups, basestring):
  145. groups = [groups]
  146. self.groups = groups
  147. self.username = username
  148. self.name = username
  149. self.email = 'foo@bar.com'
  150. self.approved_memberships = [
  151. FakeGroup('packager'),
  152. FakeGroup('design-team')
  153. ]
  154. self.dic = {}
  155. self.dic['timezone'] = 'Europe/Paris'
  156. self.login_time = datetime.utcnow()
  157. self.cla_done = cla_done
  158. def __getitem__(self, key):
  159. return self.dic[key]
  160. def create_projects(session):
  161. """ Create some projects in the database. """
  162. item = pagure.lib.model.Project(
  163. user_id=1, # pingou
  164. name='test',
  165. description='test project #1',
  166. hook_token='aaabbbccc',
  167. )
  168. session.add(item)
  169. item = pagure.lib.model.Project(
  170. user_id=1, # pingou
  171. name='test2',
  172. description='test project #2',
  173. hook_token='aaabbbddd',
  174. )
  175. session.add(item)
  176. session.commit()
  177. def create_projects_git(folder, bare=False):
  178. """ Create some projects in the database. """
  179. repos = []
  180. for project in ['test.git', 'test2.git']:
  181. repo_path = os.path.join(folder, project)
  182. repos.append(repo_path)
  183. if not os.path.exists(repo_path):
  184. os.makedirs(repo_path)
  185. pygit2.init_repository(repo_path, bare=bare)
  186. return repos
  187. def create_tokens(session, user_id=1):
  188. """ Create some tokens for the project in the database. """
  189. item = pagure.lib.model.Token(
  190. id='aaabbbcccddd',
  191. user_id=user_id,
  192. project_id=1,
  193. expiration=datetime.utcnow() + timedelta(days=30)
  194. )
  195. session.add(item)
  196. item = pagure.lib.model.Token(
  197. id='foo_token',
  198. user_id=user_id,
  199. project_id=1,
  200. expiration=datetime.utcnow() + timedelta(days=30)
  201. )
  202. session.add(item)
  203. item = pagure.lib.model.Token(
  204. id='expired_token',
  205. user_id=user_id,
  206. project_id=1,
  207. expiration=datetime.utcnow() - timedelta(days=1)
  208. )
  209. session.add(item)
  210. session.commit()
  211. def create_tokens_acl(session, token_id='aaabbbcccddd'):
  212. """ Create some acls for the tokens. """
  213. for aclid in range(len(pagure.APP.config['ACLS'])):
  214. item = pagure.lib.model.TokenAcl(
  215. token_id=token_id,
  216. acl_id=aclid + 1,
  217. )
  218. session.add(item)
  219. session.commit()
  220. def add_content_git_repo(folder):
  221. """ Create some content for the specified git repo. """
  222. if not os.path.exists(folder):
  223. os.makedirs(folder)
  224. brepo = pygit2.init_repository(folder, bare=True)
  225. newfolder = tempfile.mkdtemp(prefix='pagure-tests')
  226. repo = pygit2.clone_repository(folder, newfolder)
  227. # Create a file in that git repo
  228. with open(os.path.join(newfolder, 'sources'), 'w') as stream:
  229. stream.write('foo\n bar')
  230. repo.index.add('sources')
  231. repo.index.write()
  232. parents = []
  233. commit = None
  234. try:
  235. commit = repo.revparse_single('HEAD')
  236. except KeyError:
  237. pass
  238. if commit:
  239. parents = [commit.oid.hex]
  240. # Commits the files added
  241. tree = repo.index.write_tree()
  242. author = pygit2.Signature(
  243. 'Alice Author', 'alice@authors.tld')
  244. committer = pygit2.Signature(
  245. 'Cecil Committer', 'cecil@committers.tld')
  246. repo.create_commit(
  247. 'refs/heads/master', # the name of the reference to update
  248. author,
  249. committer,
  250. 'Add sources file for testing',
  251. # binary string representing the tree object ID
  252. tree,
  253. # list of binary strings representing parents of the new commit
  254. parents,
  255. )
  256. parents = []
  257. commit = None
  258. try:
  259. commit = repo.revparse_single('HEAD')
  260. except KeyError:
  261. pass
  262. if commit:
  263. parents = [commit.oid.hex]
  264. subfolder = os.path.join('folder1', 'folder2')
  265. if not os.path.exists(os.path.join(newfolder, subfolder)):
  266. os.makedirs(os.path.join(newfolder, subfolder))
  267. # Create a file in that git repo
  268. with open(os.path.join(newfolder, subfolder, 'file'), 'w') as stream:
  269. stream.write('foo\n bar\nbaz')
  270. repo.index.add(os.path.join(subfolder, 'file'))
  271. with open(os.path.join(newfolder, subfolder, 'fileŠ'), 'w') as stream:
  272. stream.write('foo\n bar\nbaz')
  273. repo.index.add(os.path.join(subfolder, 'fileŠ'))
  274. repo.index.write()
  275. # Commits the files added
  276. tree = repo.index.write_tree()
  277. author = pygit2.Signature(
  278. 'Alice Author', 'alice@authors.tld')
  279. committer = pygit2.Signature(
  280. 'Cecil Committer', 'cecil@committers.tld')
  281. repo.create_commit(
  282. 'refs/heads/master', # the name of the reference to update
  283. author,
  284. committer,
  285. 'Add some directory and a file for more testing',
  286. # binary string representing the tree object ID
  287. tree,
  288. # list of binary strings representing parents of the new commit
  289. parents
  290. )
  291. # Push to origin
  292. ori_remote = repo.remotes[0]
  293. master_ref = repo.lookup_reference('HEAD').resolve()
  294. refname = '%s:%s' % (master_ref.name, master_ref.name)
  295. PagureRepo.push(ori_remote, refname)
  296. shutil.rmtree(newfolder)
  297. def add_readme_git_repo(folder):
  298. """ Create a README file for the specified git repo. """
  299. if not os.path.exists(folder):
  300. os.makedirs(folder)
  301. brepo = pygit2.init_repository(folder, bare=True)
  302. newfolder = tempfile.mkdtemp(prefix='pagure-tests')
  303. repo = pygit2.clone_repository(folder, newfolder)
  304. content = """Pagure
  305. ======
  306. :Author: Pierre-Yves Chibon <pingou@pingoured.fr>
  307. Pagure is a light-weight git-centered forge based on pygit2.
  308. Currently, Pagure offers a web-interface for git repositories, a ticket
  309. system and possibilities to create new projects, fork existing ones and
  310. create/merge pull-requests across or within projects.
  311. Homepage: https://github.com/pypingou/pagure
  312. Dev instance: http://209.132.184.222/ (/!\\ May change unexpectedly, it's a dev instance ;-))
  313. """
  314. parents = []
  315. commit = None
  316. try:
  317. commit = repo.revparse_single('HEAD')
  318. except KeyError:
  319. pass
  320. if commit:
  321. parents = [commit.oid.hex]
  322. # Create a file in that git repo
  323. with open(os.path.join(newfolder, 'README.rst'), 'w') as stream:
  324. stream.write(content)
  325. repo.index.add('README.rst')
  326. repo.index.write()
  327. # Commits the files added
  328. tree = repo.index.write_tree()
  329. author = pygit2.Signature(
  330. 'Alice Author', 'alice@authors.tld')
  331. committer = pygit2.Signature(
  332. 'Cecil Committer', 'cecil@committers.tld')
  333. repo.create_commit(
  334. 'refs/heads/master', # the name of the reference to update
  335. author,
  336. committer,
  337. 'Add a README file',
  338. # binary string representing the tree object ID
  339. tree,
  340. # list of binary strings representing parents of the new commit
  341. parents
  342. )
  343. # Push to origin
  344. ori_remote = repo.remotes[0]
  345. master_ref = repo.lookup_reference('HEAD').resolve()
  346. refname = '%s:%s' % (master_ref.name, master_ref.name)
  347. PagureRepo.push(ori_remote, refname)
  348. shutil.rmtree(newfolder)
  349. def add_commit_git_repo(folder, ncommits=10, filename='sources'):
  350. """ Create some more commits for the specified git repo. """
  351. if not os.path.exists(folder):
  352. os.makedirs(folder)
  353. brepo = pygit2.init_repository(folder, bare=True)
  354. newfolder = tempfile.mkdtemp(prefix='pagure-tests')
  355. repo = pygit2.clone_repository(folder, newfolder)
  356. for index in range(ncommits):
  357. # Create a file in that git repo
  358. with open(os.path.join(newfolder, filename), 'a') as stream:
  359. stream.write('Row %s\n' % index)
  360. repo.index.add(filename)
  361. repo.index.write()
  362. parents = []
  363. commit = None
  364. try:
  365. commit = repo.revparse_single('HEAD')
  366. except KeyError:
  367. pass
  368. if commit:
  369. parents = [commit.oid.hex]
  370. # Commits the files added
  371. tree = repo.index.write_tree()
  372. author = pygit2.Signature(
  373. 'Alice Author', 'alice@authors.tld')
  374. committer = pygit2.Signature(
  375. 'Cecil Committer', 'cecil@committers.tld')
  376. repo.create_commit(
  377. 'refs/heads/master', # the name of the reference to update
  378. author,
  379. committer,
  380. 'Add row %s to %s file' % (index, filename),
  381. # binary string representing the tree object ID
  382. tree,
  383. # list of binary strings representing parents of the new commit
  384. parents,
  385. )
  386. # Push to origin
  387. ori_remote = repo.remotes[0]
  388. master_ref = repo.lookup_reference('HEAD').resolve()
  389. refname = '%s:%s' % (master_ref.name, master_ref.name)
  390. PagureRepo.push(ori_remote, refname)
  391. shutil.rmtree(newfolder)
  392. def add_binary_git_repo(folder, filename):
  393. """ Create a fake image file for the specified git repo. """
  394. if not os.path.exists(folder):
  395. os.makedirs(folder)
  396. brepo = pygit2.init_repository(folder, bare=True)
  397. newfolder = tempfile.mkdtemp(prefix='pagure-tests')
  398. repo = pygit2.clone_repository(folder, newfolder)
  399. content = b"""\x00\x00\x01\x00\x01\x00\x18\x18\x00\x00\x01\x00 \x00\x88
  400. \t\x00\x00\x16\x00\x00\x00(\x00\x00\x00\x18\x00x00\x00\x01\x00 \x00\x00\x00
  401. \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  402. 00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7lM\x01\xa6kM\t\xa6kM\x01
  403. \xa4fF\x04\xa2dE\x95\xa2cD8\xa1a
  404. """
  405. parents = []
  406. commit = None
  407. try:
  408. commit = repo.revparse_single('HEAD')
  409. except KeyError:
  410. pass
  411. if commit:
  412. parents = [commit.oid.hex]
  413. # Create a file in that git repo
  414. with open(os.path.join(newfolder, filename), 'wb') as stream:
  415. stream.write(content)
  416. repo.index.add(filename)
  417. repo.index.write()
  418. # Commits the files added
  419. tree = repo.index.write_tree()
  420. author = pygit2.Signature(
  421. 'Alice Author', 'alice@authors.tld')
  422. committer = pygit2.Signature(
  423. 'Cecil Committer', 'cecil@committers.tld')
  424. repo.create_commit(
  425. 'refs/heads/master', # the name of the reference to update
  426. author,
  427. committer,
  428. 'Add a fake image file',
  429. # binary string representing the tree object ID
  430. tree,
  431. # list of binary strings representing parents of the new commit
  432. parents
  433. )
  434. # Push to origin
  435. ori_remote = repo.remotes[0]
  436. master_ref = repo.lookup_reference('HEAD').resolve()
  437. refname = '%s:%s' % (master_ref.name, master_ref.name)
  438. PagureRepo.push(ori_remote, refname)
  439. shutil.rmtree(newfolder)
  440. if __name__ == '__main__':
  441. SUITE = unittest.TestLoader().loadTestsFromTestCase(Modeltests)
  442. unittest.TextTestRunner(verbosity=2).run(SUITE)