An ebook/comic library service and web client
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
4.0 KiB

  1. import base64
  2. import os
  3. import random
  4. import string
  5. import tempfile
  6. from typing import Tuple, Any
  7. import pytest
  8. from flask import Flask
  9. from flask.testing import FlaskClient, FlaskCliRunner
  10. from werkzeug.test import Client
  11. from atheneum import create_app, register_blueprints, register_error_handlers
  12. from atheneum.db import init_db
  13. from atheneum.model import User
  14. from atheneum.service import user_service
  15. def add_test_user() -> Tuple[str, str]:
  16. test_username = 'test_' + ''.join(
  17. random.choices(string.ascii_letters + string.digits, k=17)).strip()
  18. test_password = ''.join(
  19. random.choices(string.ascii_letters + string.digits, k=32)).strip()
  20. user_service.register(test_username, test_password, User.ROLE_ADMIN, False)
  21. return test_username, test_password
  22. @pytest.fixture
  23. def app() -> Flask:
  24. """Create and configure a new atheneum_app instance for each test."""
  25. # create a temporary file to isolate the database for each test
  26. db_fd, db_path = tempfile.mkstemp(suffix='.db')
  27. test_database_uri = 'sqlite:///{}'.format(db_path)
  28. # create the atheneum_app with common test config
  29. atheneum_app = create_app({
  30. 'TESTING': True,
  31. 'SQLALCHEMY_DATABASE_URI': test_database_uri,
  32. })
  33. register_blueprints(atheneum_app)
  34. register_error_handlers(atheneum_app)
  35. # create the database and load test data
  36. with atheneum_app.app_context():
  37. init_db()
  38. test_username, test_password = add_test_user()
  39. atheneum_app.config['test_username'] = test_username
  40. atheneum_app.config['test_password'] = test_password
  41. # get_db().executescript(_data_sql)
  42. yield atheneum_app
  43. # close and remove the temporary database
  44. os.close(db_fd)
  45. os.unlink(db_path)
  46. @pytest.fixture
  47. def client(app: Flask) -> FlaskClient:
  48. """A test client for the app."""
  49. return app.test_client()
  50. @pytest.fixture
  51. def runner(app: Flask) -> FlaskCliRunner:
  52. """A test runner for the app's Click commands."""
  53. return app.test_cli_runner()
  54. class AuthActions(object):
  55. def __init__(self,
  56. client: Client,
  57. username: str = "",
  58. password: str = "") -> None:
  59. self._client = client
  60. self.username: str = username
  61. self.password: str = password
  62. self.token: str = ""
  63. def configure(self, username: str, password: str) -> Any:
  64. self.username = username
  65. self.password = password
  66. return self
  67. def login(self) -> Any:
  68. auth_header = self.get_authorization_header_basic()
  69. result = self._client.post(
  70. '/auth/login',
  71. headers={
  72. auth_header[0]: auth_header[1]
  73. }
  74. )
  75. self.token = result.json['token']
  76. return result
  77. def bump(self) -> Any:
  78. auth_header = self.get_authorization_header_token()
  79. return self._client.post(
  80. '/auth/bump',
  81. headers={
  82. auth_header[0]: auth_header[1]
  83. }
  84. )
  85. def logout(self) -> Any:
  86. auth_header = self.get_authorization_header_token()
  87. return self._client.post(
  88. '/auth/logout',
  89. headers={
  90. auth_header[0]: auth_header[1]
  91. }
  92. )
  93. def get_authorization_header_basic(self) -> Tuple[str, str]:
  94. credentials = base64.b64encode(
  95. '{}:{}'.format(self.username, self.password).encode('utf8')) \
  96. .decode('utf8').strip()
  97. return 'Authorization', 'Basic {}'.format(credentials)
  98. def get_authorization_header_token(self) -> Tuple[str, str]:
  99. credentials = base64.b64encode(
  100. '{}:{}'.format(self.username, self.token).encode('utf8')) \
  101. .decode('utf8').strip()
  102. return 'Authorization', 'Token {}'.format(credentials)
  103. @pytest.fixture
  104. def auth(client: Client) -> AuthActions:
  105. return AuthActions(client,
  106. client.application.config.get('test_username'),
  107. client.application.config.get('test_password'))