/pgcontents/tests/utils.py

https://github.com/quantopian/pgcontents · Python · 141 lines · 95 code · 26 blank · 20 comment · 9 complexity · 060b46bbe092c6c133e61e99851bc299 MD5 · raw file

  1. # encoding: utf-8
  2. """
  3. Utilities for testing.
  4. """
  5. from __future__ import unicode_literals
  6. from contextlib import contextmanager
  7. from cryptography.fernet import Fernet
  8. from getpass import getuser
  9. from itertools import starmap
  10. import os
  11. import posixpath
  12. from unicodedata import normalize
  13. from IPython.utils import py3compat
  14. from nose.tools import nottest
  15. from sqlalchemy import create_engine
  16. from tornado.web import HTTPError
  17. from ..api_utils import api_path_join
  18. from ..crypto import FernetEncryption
  19. from ..schema import metadata
  20. from ..utils.ipycompat import (
  21. new_code_cell,
  22. new_markdown_cell,
  23. new_notebook,
  24. new_raw_cell,
  25. )
  26. from ..utils.migrate import upgrade
  27. TEST_DB_URL = os.environ.get('PGCONTENTS_TEST_DB_URL')
  28. if TEST_DB_URL is None:
  29. TEST_DB_URL = "postgresql://{user}@/pgcontents_testing".format(
  30. user=getuser(),
  31. )
  32. def make_fernet():
  33. return FernetEncryption(Fernet(Fernet.generate_key()))
  34. def _norm_unicode(s):
  35. """Normalize unicode strings"""
  36. return normalize('NFC', py3compat.cast_unicode(s))
  37. @contextmanager
  38. def assertRaisesHTTPError(testcase, status, msg=None):
  39. msg = msg or "Should have raised HTTPError(%i)" % status
  40. try:
  41. yield
  42. except HTTPError as e:
  43. testcase.assertEqual(e.status_code, status)
  44. else:
  45. testcase.fail(msg)
  46. _tables = (
  47. 'pgcontents.remote_checkpoints',
  48. 'pgcontents.files',
  49. 'pgcontents.directories',
  50. 'pgcontents.users',
  51. )
  52. unexpected_tables = set(metadata.tables) - set(_tables)
  53. if unexpected_tables:
  54. raise Exception("Unexpected tables in metadata: %s" % unexpected_tables)
  55. @nottest
  56. def clear_test_db():
  57. engine = create_engine(TEST_DB_URL)
  58. with engine.connect() as conn:
  59. for table in map(metadata.tables.__getitem__, _tables):
  60. conn.execute(table.delete())
  61. @nottest
  62. def remigrate_test_schema():
  63. """
  64. Drop recreate the test db schema.
  65. """
  66. drop_testing_db_tables()
  67. migrate_testing_db()
  68. @nottest
  69. def drop_testing_db_tables():
  70. """
  71. Drop all tables from the testing db.
  72. """
  73. engine = create_engine(TEST_DB_URL)
  74. conn = engine.connect()
  75. trans = conn.begin()
  76. conn.execute('DROP SCHEMA IF EXISTS pgcontents CASCADE')
  77. conn.execute('DROP TABLE IF EXISTS alembic_version CASCADE')
  78. trans.commit()
  79. @nottest
  80. def migrate_testing_db(revision='head'):
  81. """
  82. Migrate the testing db to the latest alembic revision.
  83. """
  84. upgrade(TEST_DB_URL, revision)
  85. @nottest
  86. def test_notebook(name):
  87. """
  88. Make a test notebook for the given name.
  89. """
  90. nb = new_notebook()
  91. nb.cells.append(new_code_cell("'code_' + '{}'".format(name)))
  92. nb.cells.append(new_raw_cell("raw_{}".format(name)))
  93. nb.cells.append(new_markdown_cell('markdown_{}'.format(name)))
  94. return nb
  95. def populate(contents_mgr):
  96. """
  97. Populate a test directory with a ContentsManager.
  98. """
  99. dirs_nbs = [
  100. ('', 'inroot.ipynb'),
  101. ('Directory with spaces in', 'inspace.ipynb'),
  102. ('unicodé', 'innonascii.ipynb'),
  103. ('foo', 'a.ipynb'),
  104. ('foo', 'name with spaces.ipynb'),
  105. ('foo', 'unicodé.ipynb'),
  106. ('foo/bar', 'baz.ipynb'),
  107. ('å b', 'ç d.ipynb'),
  108. ]
  109. for dirname, nbname in dirs_nbs:
  110. contents_mgr.save({'type': 'directory'}, path=dirname)
  111. contents_mgr.save(
  112. {'type': 'notebook', 'content': test_notebook(nbname)},
  113. path=api_path_join(dirname, nbname),
  114. )
  115. return list(starmap(posixpath.join, dirs_nbs))