__init__.py 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. # -*- coding: utf-8 -*-
  2. """Unit and functional test suite for tracim."""
  3. from os import getcwd, path
  4. import ldap3
  5. from ldap_test import LdapServer
  6. from nose.tools import ok_
  7. from paste.deploy import loadapp
  8. from webtest import TestApp
  9. from gearbox.commands.setup_app import SetupAppCommand
  10. import tg
  11. from tg import config
  12. from tg.util import Bunch
  13. from sqlalchemy.engine import reflection
  14. from sqlalchemy.schema import DropConstraint
  15. from sqlalchemy.schema import DropSequence
  16. from sqlalchemy.schema import DropTable
  17. from sqlalchemy.schema import ForeignKeyConstraint
  18. from sqlalchemy.schema import MetaData
  19. from sqlalchemy.schema import Sequence
  20. from sqlalchemy.schema import Table
  21. import transaction
  22. from who_ldap import make_connection
  23. from tracim.lib.base import logger
  24. from tracim.model import DBSession
  25. __all__ = ['setup_app', 'setup_db', 'teardown_db', 'TestController']
  26. application_name = 'main_without_authn'
  27. def load_app(name=application_name):
  28. """Load the test application."""
  29. return TestApp(loadapp('config:test.ini#%s' % name, relative_to=getcwd()))
  30. def setup_app():
  31. """Setup the application."""
  32. engine = config['tg.app_globals'].sa_engine
  33. inspector = reflection.Inspector.from_engine(engine)
  34. metadata = MetaData()
  35. logger.debug(setup_app, 'Before setup...')
  36. cmd = SetupAppCommand(Bunch(options=Bunch(verbose_level=1)), Bunch())
  37. logger.debug(setup_app, 'After setup, before run...')
  38. cmd.run(Bunch(config_file='config:test.ini', section_name=None))
  39. logger.debug(setup_app, 'After run...')
  40. def setup_db():
  41. """Create the database schema (not needed when you run setup_app)."""
  42. engine = config['tg.app_globals'].sa_engine
  43. # model.init_model(engine)
  44. # model.metadata.create_all(engine)
  45. def teardown_db():
  46. """Destroy the database schema."""
  47. engine = config['tg.app_globals'].sa_engine
  48. connection = engine.connect()
  49. # INFO - D.A. - 2014-12-04
  50. # Recipe taken from bitbucket:
  51. # https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/DropEverything
  52. inspector = reflection.Inspector.from_engine(engine)
  53. metadata = MetaData()
  54. tbs = []
  55. all_fks = []
  56. views = []
  57. # INFO - D.A. - 2014-12-04
  58. # Sequences are hard defined here because SQLA does not allow to reflect them from existing schema
  59. seqs = [
  60. Sequence('seq__groups__group_id'),
  61. Sequence('seq__contents__content_id'),
  62. Sequence('seq__content_revisions__revision_id'),
  63. Sequence('seq__permissions__permission_id'),
  64. Sequence('seq__users__user_id'),
  65. Sequence('seq__workspaces__workspace_id')
  66. ]
  67. for view_name in inspector.get_view_names():
  68. v = Table(view_name,metadata)
  69. views.append(v)
  70. for table_name in inspector.get_table_names():
  71. fks = []
  72. for fk in inspector.get_foreign_keys(table_name):
  73. if not fk['name']:
  74. continue
  75. fks.append(
  76. ForeignKeyConstraint((),(),name=fk['name'])
  77. )
  78. t = Table(table_name,metadata,*fks)
  79. tbs.append(t)
  80. all_fks.extend(fks)
  81. for fkc in all_fks:
  82. connection.execute(DropConstraint(fkc))
  83. for view in views:
  84. drop_statement = 'DROP VIEW {}'.format(view.name)
  85. # engine.execute(drop_statement)
  86. connection.execute(drop_statement)
  87. for table in tbs:
  88. connection.execute(DropTable(table))
  89. for sequence in seqs:
  90. try:
  91. connection.execute(DropSequence(sequence))
  92. except Exception as e:
  93. logger.debug(teardown_db, 'Exception while trying to remove sequence {}'.format(sequence.name))
  94. transaction.commit()
  95. engine.dispose()
  96. class TestStandard(object):
  97. application_under_test = application_name
  98. def setUp(self):
  99. self.app = load_app(self.application_under_test)
  100. logger.debug(self, 'Start setUp() by trying to clean database...')
  101. try:
  102. teardown_db()
  103. except Exception as e:
  104. logger.debug(self, 'teardown() throwed an exception {}'.format(e.__str__()))
  105. logger.debug(self, 'Start setUp() by trying to clean database... -> done')
  106. logger.debug(self, 'Start Application Setup...')
  107. setup_app()
  108. logger.debug(self, 'Start Application Setup... -> done')
  109. logger.debug(self, 'Start Database Setup...')
  110. setup_db()
  111. logger.debug(self, 'Start Database Setup... -> done')
  112. self.app.get('/_test_vars') # Allow to create fake context
  113. tg.i18n.set_lang('en') # Set a default lang
  114. def tearDown(self):
  115. transaction.commit()
  116. class TestController(object):
  117. """Base functional test case for the controllers.
  118. The tracim application instance (``self.app``) set up in this test
  119. case (and descendants) has authentication disabled, so that developers can
  120. test the protected areas independently of the :mod:`repoze.who` plugins
  121. used initially. This way, authentication can be tested once and separately.
  122. Check tracim.tests.functional.test_authentication for the repoze.who
  123. integration tests.
  124. This is the officially supported way to test protected areas with
  125. repoze.who-testutil (http://code.gustavonarea.net/repoze.who-testutil/).
  126. """
  127. application_under_test = application_name
  128. def setUp(self):
  129. """Setup test fixture for each functional test method."""
  130. self.app = load_app(self.application_under_test)
  131. try:
  132. teardown_db()
  133. except Exception as e:
  134. print('-> err ({})'.format(e.__str__()))
  135. setup_app()
  136. setup_db()
  137. def tearDown(self):
  138. """Tear down test fixture for each functional test method."""
  139. DBSession.close()
  140. teardown_db()
  141. class TracimTestController(TestController):
  142. def _connect_user(self, login, password):
  143. # Going to the login form voluntarily:
  144. resp = self.app.get('/', status=200)
  145. form = resp.form
  146. # Submitting the login form:
  147. form['login'] = login
  148. form['password'] = password
  149. return form.submit(status=302)
  150. class LDAPTest:
  151. """
  152. Server fixtures, see https://github.com/zoldar/python-ldap-test
  153. """
  154. ldap_server_data = NotImplemented
  155. def __init__(self, *args, **kwargs):
  156. super().__init__(*args, **kwargs)
  157. self._ldap_test_server = None
  158. self._ldap_connection = None
  159. def setUp(self):
  160. super().setUp()
  161. self._ldap_test_server = LdapServer(self.ldap_server_data)
  162. self._ldap_test_server.start()
  163. ldap3_server = ldap3.Server('localhost', port=self._ldap_test_server.config['port'])
  164. self._ldap_connection = ldap3.Connection(
  165. ldap3_server,
  166. user=self._ldap_test_server.config['bind_dn'],
  167. password=self._ldap_test_server.config['password'],
  168. auto_bind=True
  169. )
  170. def tearDown(self):
  171. super().tearDown()
  172. self._ldap_test_server.stop()
  173. def test_ldap_connectivity(self):
  174. with make_connection(
  175. 'ldap://%s:%d' % ('localhost', self._ldap_test_server.config['port']),
  176. self._ldap_test_server.config['bind_dn'],
  177. 'toor'
  178. ) as conn:
  179. if not conn.bind():
  180. ok_(False, "Cannot establish connection with LDAP test server")
  181. else:
  182. ok_(True)