amanuensis/tests/conftest.py

172 lines
5.2 KiB
Python
Raw Permalink Normal View History

2021-05-31 17:52:37 +00:00
"""
pytest test fixtures
"""
2021-06-17 03:17:24 +00:00
import os
2021-05-31 17:52:37 +00:00
import pytest
2021-06-17 03:17:24 +00:00
import tempfile
2021-06-26 17:13:46 +00:00
from typing import Optional
2021-06-17 03:17:24 +00:00
2021-06-26 17:13:46 +00:00
from bs4 import BeautifulSoup
from flask.testing import FlaskClient
2021-06-17 03:17:24 +00:00
from sqlalchemy.orm.session import close_all_sessions
2021-05-31 17:52:37 +00:00
from amanuensis.backend import *
2021-06-14 01:14:26 +00:00
from amanuensis.config import AmanuensisConfig
from amanuensis.db import *
2021-06-14 01:14:26 +00:00
from amanuensis.server import get_app
2021-05-31 17:52:37 +00:00
@pytest.fixture
2021-06-17 03:17:24 +00:00
def db(request) -> DbContext:
"""Provides a fully-initialized ephemeral database."""
db_fd, db_path = tempfile.mkstemp()
db = DbContext(path=db_path, echo=False)
2021-05-31 17:52:37 +00:00
db.create_all()
2021-06-17 03:17:24 +00:00
def db_teardown():
close_all_sessions()
os.close(db_fd)
os.unlink(db_path)
request.addfinalizer(db_teardown)
2021-05-31 17:52:37 +00:00
return db
2021-06-26 17:13:46 +00:00
class UserClient:
"""Class encapsulating user web operations."""
def __init__(self, db: DbContext, user_id: int):
self.db = db
self.user_id = user_id
def login(self, client: FlaskClient):
"""Log the user in."""
2021-06-29 03:56:40 +00:00
user: Optional[User] = userq.try_from_id(self.db, self.user_id)
2021-06-26 17:13:46 +00:00
assert user is not None
# Set the user's password so we know what it is later
password = os.urandom(8).hex()
userq.password_set(self.db, user.username, password)
# Log in
response = client.get("/auth/login/")
assert response.status_code == 200
soup = BeautifulSoup(response.data, features="html.parser")
csrf_token = soup.find(id="csrf_token")
assert csrf_token is not None
response = client.post(
"/auth/login/",
data={
"username": user.username,
"password": password,
"csrf_token": csrf_token["value"],
},
)
assert 300 <= response.status_code <= 399
def logout(self, client: FlaskClient):
"""Log the user out."""
response = client.get("/auth/logout/")
assert 300 <= response.status_code <= 399
class ObjectFactory:
"""Factory class."""
def __init__(self, db):
self.db = db
2021-06-03 03:05:33 +00:00
2021-06-26 17:13:46 +00:00
def user(self, state={"nonce": 1}, **kwargs) -> User:
"""Factory function for creating users, with valid default values."""
default_kwargs: dict = {
2021-06-03 03:10:34 +00:00
"username": f'test_user_{state["nonce"]}',
"password": "password",
"display_name": None,
"email": "user@example.com",
"is_site_admin": False,
2021-05-31 17:52:37 +00:00
}
2021-06-03 03:10:34 +00:00
state["nonce"] += 1
2021-06-26 17:13:46 +00:00
updated_kwargs: dict = {**default_kwargs, **kwargs}
return userq.create(self.db, **updated_kwargs)
2021-05-31 17:52:37 +00:00
2021-06-26 17:13:46 +00:00
def lexicon(self, state={"nonce": 1}, **kwargs) -> Lexicon:
"""Factory function for creating lexicons, with valid default values."""
default_kwargs: dict = {
2021-06-03 03:10:34 +00:00
"name": f'Test_{state["nonce"]}',
"title": None,
"prompt": f'Test Lexicon game {state["nonce"]}',
2021-05-31 17:52:37 +00:00
}
2021-06-03 03:10:34 +00:00
state["nonce"] += 1
2021-06-26 17:13:46 +00:00
updated_kwargs: dict = {**default_kwargs, **kwargs}
lex = lexiq.create(self.db, **updated_kwargs)
lex.joinable = True
2021-06-26 17:13:46 +00:00
self.db.session.commit()
return lex
2021-06-03 03:05:33 +00:00
2021-06-26 17:13:46 +00:00
def membership(self, **kwargs) -> Membership:
"""Factory function for creating memberships, with valid default values."""
default_kwargs: dict = {
2021-06-03 03:10:34 +00:00
"is_editor": False,
2021-05-31 17:52:37 +00:00
}
2021-06-26 17:13:46 +00:00
updated_kwargs: dict = {**default_kwargs, **kwargs}
return memq.create(self.db, **updated_kwargs)
2021-06-03 03:05:33 +00:00
2021-06-26 17:13:46 +00:00
def character(self, state={"nonce": 1}, **kwargs) -> Character:
"""Factory function for creating characters, with valid default values."""
default_kwargs: dict = {
2021-06-03 03:10:34 +00:00
"name": f'Character {state["nonce"]}',
"signature": None,
2021-06-02 01:46:19 +00:00
}
2021-06-03 03:10:34 +00:00
state["nonce"] += 1
2021-06-26 17:13:46 +00:00
updated_kwargs: dict = {**default_kwargs, **kwargs}
return charq.create(self.db, **updated_kwargs)
2021-06-03 03:05:33 +00:00
def index(self, state={"nonce": ord("A")}, **kwargs) -> ArticleIndex:
"""Factory function for creating indices, with valid defaut values."""
default_kwargs: dict = {
"index_type": IndexType.CHAR,
"pattern": chr(state["nonce"]),
"logical_order": 0,
"display_order": 0,
"capacity": None,
}
state["nonce"] += 1
updated_kwargs = {**default_kwargs, **kwargs}
return indq.create(self.db, **updated_kwargs)
2021-06-26 17:13:46 +00:00
def client(self, user_id: int) -> UserClient:
"""Factory function for user test clients."""
return UserClient(self.db, user_id)
2021-06-02 01:46:19 +00:00
@pytest.fixture
2021-06-26 17:13:46 +00:00
def make(db: DbContext) -> ObjectFactory:
"""Fixture that provides a factory class."""
return ObjectFactory(db)
2021-06-02 01:46:19 +00:00
@pytest.fixture
2021-06-26 17:13:46 +00:00
def lexicon_with_editor(make: ObjectFactory):
2021-05-31 17:52:37 +00:00
"""Shortcut setup for a lexicon game with an editor."""
2021-06-02 01:46:19 +00:00
editor = make.user()
2021-05-31 17:52:37 +00:00
assert editor
2021-06-02 01:46:19 +00:00
lexicon = make.lexicon()
2021-05-31 17:52:37 +00:00
assert lexicon
2021-06-03 03:05:33 +00:00
membership = make.membership(
user_id=editor.id, lexicon_id=lexicon.id, is_editor=True
)
2021-05-31 17:52:37 +00:00
assert membership
return (lexicon, editor)
2021-06-14 01:14:26 +00:00
class TestConfig(AmanuensisConfig):
TESTING = True
2021-06-17 03:17:24 +00:00
SECRET_KEY = os.urandom(32).hex()
2021-06-14 01:14:26 +00:00
@pytest.fixture
2021-06-17 03:17:24 +00:00
def app(db: DbContext):
2021-06-14 01:14:26 +00:00
"""Provides an application running on top of the test database."""
2021-06-17 03:17:24 +00:00
return get_app(TestConfig(), db)