__init__.py 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. # -*- coding: utf-8 -*-
  2. import unittest
  3. import plaster
  4. import requests
  5. import transaction
  6. from depot.manager import DepotManager
  7. from pyramid import testing
  8. from sqlalchemy.exc import IntegrityError
  9. from tracim_backend.lib.core.content import ContentApi
  10. from tracim_backend.lib.core.workspace import WorkspaceApi
  11. from tracim_backend.models import get_engine
  12. from tracim_backend.models import DeclarativeBase
  13. from tracim_backend.models import get_session_factory
  14. from tracim_backend.models import get_tm_session
  15. from tracim_backend.models.contents import CONTENT_TYPES
  16. from tracim_backend.models.data import Workspace
  17. from tracim_backend.models.data import ContentRevisionRO
  18. from tracim_backend.models.data import Content
  19. from tracim_backend.lib.utils.logger import logger
  20. from tracim_backend.fixtures import FixturesLoader
  21. from tracim_backend.fixtures.users_and_groups import Base as BaseFixture
  22. from tracim_backend.config import CFG
  23. from tracim_backend.extensions import hapic
  24. from tracim_backend import web
  25. from webtest import TestApp
  26. from io import BytesIO
  27. from PIL import Image
  28. def eq_(a, b, msg=None):
  29. # TODO - G.M - 05-04-2018 - Remove this when all old nose code is removed
  30. assert a == b, msg or "%r != %r" % (a, b)
  31. # TODO - G.M - 2018-06-179 - Refactor slug change function
  32. # as a kind of pytest fixture ?
  33. def set_html_document_slug_to_legacy(session_factory) -> None:
  34. """
  35. Simple function to help some functional test. This modify "html-documents"
  36. type content in database to legacy "page" slug.
  37. :param session_factory: session factory of the test
  38. :return: Nothing.
  39. """
  40. dbsession = get_tm_session(
  41. session_factory,
  42. transaction.manager
  43. )
  44. content_query = dbsession.query(ContentRevisionRO).filter(ContentRevisionRO.type == 'page').filter(ContentRevisionRO.content_id == 6) # nopep8
  45. assert content_query.count() == 0
  46. html_documents_query = dbsession.query(ContentRevisionRO).filter(ContentRevisionRO.type == 'html-document') # nopep8
  47. html_documents_query.update({ContentRevisionRO.type: 'page'})
  48. transaction.commit()
  49. assert content_query.count() > 0
  50. def create_1000px_png_test_image():
  51. file = BytesIO()
  52. image = Image.new('RGBA', size=(1000, 1000), color=(0, 0, 0))
  53. image.save(file, 'png')
  54. file.name = 'test_image.png'
  55. file.seek(0)
  56. return file
  57. class FunctionalTest(unittest.TestCase):
  58. fixtures = [BaseFixture]
  59. sqlalchemy_url = 'sqlite:///tracim_test.sqlite'
  60. def setUp(self):
  61. logger._logger.setLevel('WARNING')
  62. DepotManager._clear()
  63. self.settings = {
  64. 'sqlalchemy.url': self.sqlalchemy_url,
  65. 'user.auth_token.validity': '604800',
  66. 'depot_storage_dir': '/tmp/test/depot',
  67. 'depot_storage_name': 'test',
  68. 'preview_cache_dir': '/tmp/test/preview_cache',
  69. 'preview.jpg.restricted_dims': True,
  70. 'email.notification.activated': 'false',
  71. }
  72. hapic.reset_context()
  73. self.engine = get_engine(self.settings)
  74. DeclarativeBase.metadata.create_all(self.engine)
  75. self.session_factory = get_session_factory(self.engine)
  76. self.app_config = CFG(self.settings)
  77. self.app_config.configure_filedepot()
  78. self.init_database(self.settings)
  79. DepotManager._clear()
  80. self.run_app()
  81. def run_app(self):
  82. app = web({}, **self.settings)
  83. self.testapp = TestApp(app)
  84. def init_database(self, settings):
  85. with transaction.manager:
  86. dbsession = get_tm_session(self.session_factory, transaction.manager)
  87. try:
  88. fixtures_loader = FixturesLoader(dbsession, self.app_config)
  89. fixtures_loader.loads(self.fixtures)
  90. transaction.commit()
  91. print("Database initialized.")
  92. except IntegrityError:
  93. print('Warning, there was a problem when adding default data'
  94. ', it may have already been added:')
  95. import traceback
  96. print(traceback.format_exc())
  97. transaction.abort()
  98. print('Database initialization failed')
  99. def tearDown(self):
  100. logger.debug(self, 'TearDown Test...')
  101. from tracim_backend.models.meta import DeclarativeBase
  102. testing.tearDown()
  103. transaction.abort()
  104. DeclarativeBase.metadata.drop_all(self.engine)
  105. DepotManager._clear()
  106. class FunctionalTestEmptyDB(FunctionalTest):
  107. fixtures = []
  108. class FunctionalTestNoDB(FunctionalTest):
  109. sqlalchemy_url = 'sqlite://'
  110. def init_database(self, settings):
  111. self.engine = get_engine(settings)
  112. class CommandFunctionalTest(FunctionalTest):
  113. def run_app(self):
  114. self.session = get_tm_session(self.session_factory, transaction.manager)
  115. class BaseTest(unittest.TestCase):
  116. """
  117. Pyramid default test.
  118. """
  119. config_uri = 'tests_configs.ini'
  120. config_section = 'base_test'
  121. def setUp(self):
  122. logger._logger.setLevel('WARNING')
  123. logger.debug(self, 'Setup Test...')
  124. self.settings = plaster.get_settings(
  125. self.config_uri,
  126. self.config_section
  127. )
  128. self.config = testing.setUp(settings = self.settings)
  129. self.config.include('tracim_backend.models')
  130. DepotManager._clear()
  131. DepotManager.configure(
  132. 'test', {'depot.backend': 'depot.io.memory.MemoryFileStorage'}
  133. )
  134. settings = self.config.get_settings()
  135. self.app_config = CFG(settings)
  136. from tracim_backend.models import (
  137. get_engine,
  138. get_session_factory,
  139. get_tm_session,
  140. )
  141. self.engine = get_engine(settings)
  142. session_factory = get_session_factory(self.engine)
  143. self.session = get_tm_session(session_factory, transaction.manager)
  144. self.init_database()
  145. def init_database(self):
  146. logger.debug(self, 'Init Database Schema...')
  147. from tracim_backend.models.meta import DeclarativeBase
  148. DeclarativeBase.metadata.create_all(self.engine)
  149. def tearDown(self):
  150. logger.debug(self, 'TearDown Test...')
  151. from tracim_backend.models.meta import DeclarativeBase
  152. testing.tearDown()
  153. transaction.abort()
  154. DeclarativeBase.metadata.drop_all(self.engine)
  155. class StandardTest(BaseTest):
  156. """
  157. BaseTest with default fixtures
  158. """
  159. fixtures = [BaseFixture]
  160. def init_database(self):
  161. BaseTest.init_database(self)
  162. fixtures_loader = FixturesLoader(
  163. session=self.session,
  164. config=CFG(self.config.get_settings()))
  165. fixtures_loader.loads(self.fixtures)
  166. class DefaultTest(StandardTest):
  167. def _create_workspace_and_test(self, name, user) -> Workspace:
  168. """
  169. All extra parameters (*args, **kwargs) are for Workspace init
  170. :return: Created workspace instance
  171. """
  172. WorkspaceApi(
  173. current_user=user,
  174. session=self.session,
  175. config=self.app_config,
  176. ).create_workspace(name, save_now=True)
  177. eq_(
  178. 1,
  179. self.session.query(Workspace).filter(
  180. Workspace.label == name
  181. ).count()
  182. )
  183. return self.session.query(Workspace).filter(
  184. Workspace.label == name
  185. ).one()
  186. def _create_content_and_test(
  187. self,
  188. name,
  189. workspace,
  190. *args,
  191. **kwargs
  192. ) -> Content:
  193. """
  194. All extra parameters (*args, **kwargs) are for Content init
  195. :return: Created Content instance
  196. """
  197. content = Content(*args, **kwargs)
  198. content.label = name
  199. content.workspace = workspace
  200. self.session.add(content)
  201. self.session.flush()
  202. content_api = ContentApi(
  203. current_user=None,
  204. session=self.session,
  205. config=self.app_config,
  206. )
  207. eq_(
  208. 1,
  209. content_api.get_canonical_query().filter(
  210. Content.label == name
  211. ).count()
  212. )
  213. return content_api.get_canonical_query().filter(
  214. Content.label == name
  215. ).one()
  216. def _create_thread_and_test(self,
  217. user,
  218. workspace_name='workspace_1',
  219. folder_name='folder_1',
  220. thread_name='thread_1') -> Content:
  221. """
  222. :return: Thread
  223. """
  224. workspace = self._create_workspace_and_test(workspace_name, user)
  225. folder = self._create_content_and_test(
  226. folder_name, workspace,
  227. type=CONTENT_TYPES.Folder.slug,
  228. owner=user
  229. )
  230. thread = self._create_content_and_test(
  231. thread_name,
  232. workspace,
  233. type=CONTENT_TYPES.Thread.slug,
  234. parent=folder,
  235. owner=user
  236. )
  237. return thread
  238. class MailHogTest(DefaultTest):
  239. """
  240. Theses test need a working mailhog
  241. """
  242. config_section = 'mail_test'
  243. def tearDown(self):
  244. logger.debug(self, 'Cleanup MailHog list...')
  245. requests.delete('http://127.0.0.1:8025/api/v1/messages')