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.
139 lines
4.3 KiB
139 lines
4.3 KiB
import base64
|
|
import os
|
|
import random
|
|
import string
|
|
import tempfile
|
|
from typing import Tuple, Any, Generator
|
|
|
|
import pytest
|
|
from flask import Flask
|
|
from flask.testing import FlaskClient, FlaskCliRunner
|
|
from werkzeug.test import Client
|
|
|
|
from server import create_app, register_blueprints, register_error_handlers
|
|
from server.db import init_db
|
|
from server.model import User
|
|
from server.service import user_service
|
|
|
|
|
|
def add_test_user() -> Tuple[str, str]:
|
|
test_username = 'test_' + ''.join(
|
|
random.choices(string.ascii_letters + string.digits, k=17)).strip()
|
|
test_password = ''.join(
|
|
random.choices(string.ascii_letters + string.digits, k=32)).strip()
|
|
user_service.register(test_username, test_password, User.ROLE_ADMIN, False)
|
|
return test_username, test_password
|
|
|
|
|
|
@pytest.fixture
|
|
def app() -> Generator[Flask, Any, Any]:
|
|
"""Create and configure a new server_app instance for each test."""
|
|
# create a temporary file to isolate the database for each test
|
|
db_fd, db_path = tempfile.mkstemp(suffix='.db')
|
|
test_database_uri = 'sqlite:///{}'.format(db_path)
|
|
# create the server_app with common test config
|
|
server_app = create_app({
|
|
'TESTING': True,
|
|
'SQLALCHEMY_DATABASE_URI': test_database_uri,
|
|
})
|
|
test_settings = 'tests.test_settings'
|
|
server_app.logger.debug('Loading configuration from ' + test_settings)
|
|
server_app.config.from_object(test_settings)
|
|
register_blueprints(server_app)
|
|
register_error_handlers(server_app)
|
|
|
|
# create the database and load test data
|
|
with server_app.app_context():
|
|
init_db()
|
|
test_username, test_password = add_test_user()
|
|
server_app.config['test_username'] = test_username
|
|
server_app.config['test_password'] = test_password
|
|
# get_db().executescript(_data_sql)
|
|
|
|
yield server_app
|
|
|
|
# close and remove the temporary database
|
|
os.close(db_fd)
|
|
os.unlink(db_path)
|
|
|
|
|
|
@pytest.fixture
|
|
def client(app: Flask) -> FlaskClient:
|
|
"""A test client for the app."""
|
|
return app.test_client()
|
|
|
|
|
|
@pytest.fixture
|
|
def runner(app: Flask) -> FlaskCliRunner:
|
|
"""A test runner for the app's Click commands."""
|
|
return app.test_cli_runner()
|
|
|
|
|
|
class AuthActions(object):
|
|
def __init__(self,
|
|
client: Client,
|
|
username: str = "",
|
|
password: str = "") -> None:
|
|
self._client = client
|
|
self.username: str = username
|
|
self.password: str = password
|
|
self.token: str = ""
|
|
|
|
def configure(self, username: str, password: str) -> Any:
|
|
self.username = username
|
|
self.password = password
|
|
return self
|
|
|
|
def login(self) -> Any:
|
|
auth_header = self.get_authorization_header_basic()
|
|
result = self._client.post(
|
|
'/auth/login',
|
|
headers={
|
|
auth_header[0]: auth_header[1]
|
|
}
|
|
)
|
|
self.token = result.json['token']
|
|
return result
|
|
|
|
def bump(self) -> Any:
|
|
auth_header = self.get_authorization_header_token()
|
|
return self._client.post(
|
|
'/auth/bump',
|
|
headers={
|
|
auth_header[0]: auth_header[1]
|
|
}
|
|
)
|
|
|
|
def logout(self) -> Any:
|
|
auth_header = self.get_authorization_header_token()
|
|
return self._client.post(
|
|
'/auth/logout',
|
|
headers={
|
|
auth_header[0]: auth_header[1]
|
|
}
|
|
)
|
|
|
|
def get_authorization_header_basic(self) -> Tuple[str, str]:
|
|
credentials = base64.b64encode(
|
|
'{}:{}'.format(self.username, self.password).encode('utf8')) \
|
|
.decode('utf8').strip()
|
|
return 'Authorization', 'Basic {}'.format(credentials)
|
|
|
|
def get_authorization_header_token(self) -> Tuple[str, str]:
|
|
credentials = base64.b64encode(
|
|
'{}:{}'.format(self.username, self.token).encode('utf8')) \
|
|
.decode('utf8').strip()
|
|
return 'X-Auth-Token', '{}'.format(credentials)
|
|
|
|
def __enter__(self) -> 'AuthActions':
|
|
return self.login()
|
|
|
|
def __exit__(self, type: Any, value: Any, traceback: Any) -> None:
|
|
self.logout()
|
|
|
|
|
|
@pytest.fixture
|
|
def auth(client: Client) -> AuthActions:
|
|
return AuthActions(client,
|
|
client.application.config.get('test_username'),
|
|
client.application.config.get('test_password'))
|