__init__.py 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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.app_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. config_uri = 'tests_configs.ini'
  60. config_section = 'functional_test'
  61. def setUp(self):
  62. logger._logger.setLevel('WARNING')
  63. DepotManager._clear()
  64. self.settings = plaster.get_settings(
  65. self.config_uri,
  66. self.config_section
  67. )
  68. hapic.reset_context()
  69. self.engine = get_engine(self.settings)
  70. DeclarativeBase.metadata.create_all(self.engine)
  71. self.session_factory = get_session_factory(self.engine)
  72. self.app_config = CFG(self.settings)
  73. self.app_config.configure_filedepot()
  74. self.init_database(self.settings)
  75. DepotManager._clear()
  76. self.run_app()
  77. def run_app(self):
  78. app = web({}, **self.settings)
  79. self.testapp = TestApp(app)
  80. def init_database(self, settings):
  81. with transaction.manager:
  82. dbsession = get_tm_session(self.session_factory, transaction.manager)
  83. try:
  84. fixtures_loader = FixturesLoader(dbsession, self.app_config)
  85. fixtures_loader.loads(self.fixtures)
  86. transaction.commit()
  87. print("Database initialized.")
  88. except IntegrityError:
  89. print('Warning, there was a problem when adding default data'
  90. ', it may have already been added:')
  91. import traceback
  92. print(traceback.format_exc())
  93. transaction.abort()
  94. print('Database initialization failed')
  95. def tearDown(self):
  96. logger.debug(self, 'TearDown Test...')
  97. from tracim_backend.models.meta import DeclarativeBase
  98. testing.tearDown()
  99. transaction.abort()
  100. DeclarativeBase.metadata.drop_all(self.engine)
  101. DepotManager._clear()
  102. class FunctionalTestEmptyDB(FunctionalTest):
  103. fixtures = []
  104. class FunctionalTestNoDB(FunctionalTest):
  105. config_section = 'functional_test_no_db'
  106. def init_database(self, settings):
  107. self.engine = get_engine(settings)
  108. class CommandFunctionalTest(FunctionalTest):
  109. def run_app(self):
  110. self.session = get_tm_session(self.session_factory, transaction.manager)
  111. class BaseTest(unittest.TestCase):
  112. """
  113. Pyramid default test.
  114. """
  115. config_uri = 'tests_configs.ini'
  116. config_section = 'base_test'
  117. def setUp(self):
  118. logger._logger.setLevel('WARNING')
  119. logger.debug(self, 'Setup Test...')
  120. self.settings = plaster.get_settings(
  121. self.config_uri,
  122. self.config_section
  123. )
  124. self.config = testing.setUp(settings = self.settings)
  125. self.config.include('tracim_backend.models')
  126. DepotManager._clear()
  127. DepotManager.configure(
  128. 'test', {'depot.backend': 'depot.io.memory.MemoryFileStorage'}
  129. )
  130. settings = self.config.get_settings()
  131. self.app_config = CFG(settings)
  132. from tracim_backend.models import (
  133. get_engine,
  134. get_session_factory,
  135. get_tm_session,
  136. )
  137. self.engine = get_engine(settings)
  138. session_factory = get_session_factory(self.engine)
  139. self.session = get_tm_session(session_factory, transaction.manager)
  140. self.init_database()
  141. def init_database(self):
  142. logger.debug(self, 'Init Database Schema...')
  143. from tracim_backend.models.meta import DeclarativeBase
  144. DeclarativeBase.metadata.create_all(self.engine)
  145. def tearDown(self):
  146. logger.debug(self, 'TearDown Test...')
  147. from tracim_backend.models.meta import DeclarativeBase
  148. testing.tearDown()
  149. transaction.abort()
  150. DeclarativeBase.metadata.drop_all(self.engine)
  151. class StandardTest(BaseTest):
  152. """
  153. BaseTest with default fixtures
  154. """
  155. fixtures = [BaseFixture]
  156. def init_database(self):
  157. BaseTest.init_database(self)
  158. fixtures_loader = FixturesLoader(
  159. session=self.session,
  160. config=CFG(self.config.get_settings()))
  161. fixtures_loader.loads(self.fixtures)
  162. class DefaultTest(StandardTest):
  163. def _create_workspace_and_test(self, name, user) -> Workspace:
  164. """
  165. All extra parameters (*args, **kwargs) are for Workspace init
  166. :return: Created workspace instance
  167. """
  168. WorkspaceApi(
  169. current_user=user,
  170. session=self.session,
  171. config=self.app_config,
  172. ).create_workspace(name, save_now=True)
  173. eq_(
  174. 1,
  175. self.session.query(Workspace).filter(
  176. Workspace.label == name
  177. ).count()
  178. )
  179. return self.session.query(Workspace).filter(
  180. Workspace.label == name
  181. ).one()
  182. def _create_content_and_test(
  183. self,
  184. name,
  185. workspace,
  186. *args,
  187. **kwargs
  188. ) -> Content:
  189. """
  190. All extra parameters (*args, **kwargs) are for Content init
  191. :return: Created Content instance
  192. """
  193. content = Content(*args, **kwargs)
  194. content.label = name
  195. content.workspace = workspace
  196. self.session.add(content)
  197. self.session.flush()
  198. content_api = ContentApi(
  199. current_user=None,
  200. session=self.session,
  201. config=self.app_config,
  202. )
  203. eq_(
  204. 1,
  205. content_api.get_canonical_query().filter(
  206. Content.label == name
  207. ).count()
  208. )
  209. return content_api.get_canonical_query().filter(
  210. Content.label == name
  211. ).one()
  212. def _create_thread_and_test(self,
  213. user,
  214. workspace_name='workspace_1',
  215. folder_name='folder_1',
  216. thread_name='thread_1') -> Content:
  217. """
  218. :return: Thread
  219. """
  220. workspace = self._create_workspace_and_test(workspace_name, user)
  221. folder = self._create_content_and_test(
  222. folder_name, workspace,
  223. type=CONTENT_TYPES.Folder.slug,
  224. owner=user
  225. )
  226. thread = self._create_content_and_test(
  227. thread_name,
  228. workspace,
  229. type=CONTENT_TYPES.Thread.slug,
  230. parent=folder,
  231. owner=user
  232. )
  233. return thread
  234. class MailHogTest(DefaultTest):
  235. """
  236. Theses test need a working mailhog
  237. """
  238. config_section = 'mail_test'
  239. def tearDown(self):
  240. logger.debug(self, 'Cleanup MailHog list...')
  241. requests.delete('http://127.0.0.1:8025/api/v1/messages')