Add new testing suite with working fixture

This commit is contained in:
2025-06-25 09:28:09 +00:00
parent 74a57700c8
commit 81bae580f9
16 changed files with 62 additions and 57 deletions
+20 -11
View File
@@ -11,14 +11,20 @@ modules: dict[str, Any] = {
] ]
} }
TORTOISE_ORM = { TEST_TORTOISE_ORM = {
"connections": { "connections": {
"testing": { "default": "sqlite://:memory:"
"engine": "tortoise.backends.sqlite", },
"credentials": { "apps": {
"file_path": "stoneedge.sqlite" "models": {
} "models": modules.get("models", []) + ["aerich.models"],
"default_connection": "default",
}, },
},
}
PROD_TORTOISE_ORM = {
"connections": {
"default": { "default": {
"engine": "tortoise.backends.asyncpg", "engine": "tortoise.backends.asyncpg",
"credentials": { "credentials": {
@@ -28,23 +34,26 @@ TORTOISE_ORM = {
"password": settings.PSQL_PASSWORD, "password": settings.PSQL_PASSWORD,
"port": settings.PSQL_PORT, "port": settings.PSQL_PORT,
}, },
} },
}, },
"apps": { "apps": {
"models": { "models": {
"models": modules.get("models", []) + ["aerich.models"], "models": modules.get("models", []) + ["aerich.models"],
"default_connection": "testing" if settings.IS_TESTING else "default", "default_connection": "default",
}, },
}, },
} }
async def migrate_db(tortoise_config=TORTOISE_ORM): async def migrate_db(tortoise_config=PROD_TORTOISE_ORM):
if settings.IS_TESTING:
tortoise_config=TEST_TORTOISE_ORM
aerich = Command(tortoise_config) aerich = Command(tortoise_config)
await aerich.init() await aerich.init()
await aerich.upgrade(run_in_transaction=True) await aerich.upgrade()
await Tortoise.init(tortoise_config) await Tortoise.init(tortoise_config)
await Tortoise.generate_schemas(safe=True) await Tortoise.generate_schemas(safe=True)
async def end_connections_to_db(): async def end_connections_to_db():
await Tortoise.close_connections() await Tortoise.close_connections()
+3 -1
View File
@@ -31,7 +31,9 @@ async def login(form: Annotated[OAuth2PasswordRequestForm, Depends()]):
Logs the user into our API, creates tokens and passes them back to User. Logs the user into our API, creates tokens and passes them back to User.
""" """
user: User | None = await User.filter(email=form.username).first() user: User | None = await User.filter(Q(email=form.username) | Q(username=form.username)).first()
print(user)
if user is None: if user is None:
raise HTTPException(status_code=401, detail=account_error) raise HTTPException(status_code=401, detail=account_error)
+1 -2
View File
@@ -1,5 +1,4 @@
import pytest
@pytest.mark.usefixtures("use_database_during_testing")
class Test(): class Test():
pass pass
+1 -11
View File
@@ -1,11 +1,8 @@
import asyncio import asyncio, httpx, pytest
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from typing import AsyncGenerator from typing import AsyncGenerator
import httpx, pytest
from tortoise import Tortoise
from asgi_lifespan import LifespanManager from asgi_lifespan import LifespanManager
from database import migrate_db
from tests.fixtures.account import * from tests.fixtures.account import *
try: try:
@@ -32,13 +29,6 @@ def event_loop():
loop.close() loop.close()
@pytest.fixture
async def use_database_during_testing():
await migrate_db()
yield
await Tortoise._drop_databases()
@asynccontextmanager @asynccontextmanager
async def client_manager(app, base_url="https://localhost", **kw) -> ClientManagerType: async def client_manager(app, base_url="https://localhost", **kw) -> ClientManagerType:
app.state.testing = True app.state.testing = True
View File
+33 -23
View File
@@ -5,6 +5,7 @@ from modules.auth.utils import create_jwt_tokens
from modules.organizations.models import Organization, OrganizationType from modules.organizations.models import Organization, OrganizationType
from modules.users.models import ACL, Membership, User from modules.users.models import ACL, Membership, User
from modules.auth.models import Token from modules.auth.models import Token
from tortoise.expressions import Q
from config import settings from config import settings
@@ -27,32 +28,41 @@ async def create_user_with_org():
organization_name="simple organization", organization_name="simple organization",
organization_type=OrganizationType.HOME, organization_type=OrganizationType.HOME,
is_admin=False) -> user_creation_return_type: is_admin=False) -> user_creation_return_type:
org: Organization = await Organization.create( org: Organization | None = await Organization.filter(Q(name=organization_name) & Q(name=organization_type)).first()
name=organization_name, if not org:
type=organization_type org: Organization = await Organization.create(
) name=organization_name,
type=organization_type
)
acl: ACL = await ACL.create( user: User | None = await User.filter(Q(email=email)).first()
READ=True, if not user:
WRITE=True, user: User = await User.create(
REPORT=True, email=email,
MANAGE=True if is_admin else False, username=username,
ADMIN=True if is_admin else False, name=name,
) surname=surname,
password=crypt.hash(password),
)
user: User = await User.create( acl: ACL | None = await ACL.filter(Q(id="5f33facd-08dd-48a1-8f15-3b24f2a727f5")).first()
email=email, if not acl:
username=username, acl: ACL = await ACL.create(
name=name, id="5f33facd-08dd-48a1-8f15-3b24f2a727f5",
surname=surname, READ=True,
password=crypt.hash(password), WRITE=True,
) REPORT=True,
MANAGE=True if is_admin else False,
ADMIN=True if is_admin else False,
)
await Membership.create( membership: Membership | None = await Membership.filter(Q(user=user, organization=org, acl=acl)).first()
organization=org, if not membership:
user=user, await Membership.get_or_create(
acl=acl organization=org,
) user=user,
acl=acl
)
tokens: Token = await create_jwt_tokens(user=user) tokens: Token = await create_jwt_tokens(user=user)
@@ -10,7 +10,6 @@ crypt = settings.CRYPT
class TestAuthentication(Test): class TestAuthentication(Test):
@pytest.mark.asyncio
async def test_authentication_with_non_existing_user_and_password( async def test_authentication_with_non_existing_user_and_password(
self, client: AsyncClient self, client: AsyncClient
): ):
@@ -25,7 +24,6 @@ class TestAuthentication(Test):
assert response.status_code == 401 assert response.status_code == 401
assert response.json() == {"detail": "E-Mail Address or password is incorrect"} assert response.json() == {"detail": "E-Mail Address or password is incorrect"}
@pytest.mark.asyncio
async def test_authentication_with_existing_user_and_wrong_password( async def test_authentication_with_existing_user_and_wrong_password(
self, client: AsyncClient, create_user_with_org self, client: AsyncClient, create_user_with_org
): ):
@@ -41,7 +39,6 @@ class TestAuthentication(Test):
assert response.status_code == 401 assert response.status_code == 401
assert response.json() == {"detail": "E-Mail Address or password is incorrect"} assert response.json() == {"detail": "E-Mail Address or password is incorrect"}
@pytest.mark.asyncio
async def test_authentication_with_existing_user_and_password( async def test_authentication_with_existing_user_and_password(
self, client: AsyncClient, create_user_with_org self, client: AsyncClient, create_user_with_org
): ):
@@ -69,19 +66,19 @@ class TestAuthentication(Test):
} }
} }
@pytest.mark.asyncio
async def test_logging_out_destroys_tokens( async def test_logging_out_destroys_tokens(
self, client: AsyncClient, create_user_with_org self, client: AsyncClient, create_user_with_org
): ):
user, _, _, _ = await create_user_with_org(email="user@localhost.com", password="userpassword") user, _, _, _ = await create_user_with_org(email="superuser@localhost.com", password="superuser")
response = await client.post( response = await client.post(
"https://localhost/api/v1/auth/login", "https://localhost/api/v1/auth/login",
data={ data={
"username": "user@localhost.com", "username": "superuser@localhost.com",
"password": "userpassword", "password": "superuser",
"grant_type": "password", "grant_type": "password",
}, },
) )
print(response.json())
assert response.status_code == 200 assert response.status_code == 200
assert response.json() == { assert response.json() == {
"jwt": { "jwt": {
@@ -116,7 +113,6 @@ class TestAuthentication(Test):
"detail": "Refresh token not found or something went wrong." "detail": "Refresh token not found or something went wrong."
} }
@pytest.mark.asyncio
async def test_create_new_tokens_upon_refresh( async def test_create_new_tokens_upon_refresh(
self, client: AsyncClient, create_user_with_org self, client: AsyncClient, create_user_with_org
): ):
@@ -166,7 +162,6 @@ class TestAuthentication(Test):
} }
} }
@pytest.mark.asyncio
async def test_setup_new_account(self, client: AsyncClient): async def test_setup_new_account(self, client: AsyncClient):
# Ensure account is never available. Prevents account already being available. # Ensure account is never available. Prevents account already being available.
check_if_account_exists: User | None = await User.filter( check_if_account_exists: User | None = await User.filter(