✨ Added new tests and fixed small bugs
This commit is contained in:
@@ -2,7 +2,6 @@
|
|||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
@@ -13,7 +12,6 @@ from pydantic import BaseModel, Json, validator
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from . import metadata, database
|
from . import metadata, database
|
||||||
from .quiztivity import QuizTivityPage
|
from .quiztivity import QuizTivityPage
|
||||||
from ..config import server_regex
|
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
|
|
||||||
|
|
||||||
@@ -165,15 +163,6 @@ class QuizInput(BaseModel):
|
|||||||
questions: list[QuizQuestion]
|
questions: list[QuizQuestion]
|
||||||
background_image: str | None
|
background_image: str | None
|
||||||
|
|
||||||
@validator("background_image")
|
|
||||||
def must_come_from_local_cdn(cls, v):
|
|
||||||
if v is None:
|
|
||||||
return v
|
|
||||||
elif bool(re.match(server_regex, v)):
|
|
||||||
return v
|
|
||||||
else:
|
|
||||||
raise ValueError("does not match url scheme")
|
|
||||||
|
|
||||||
|
|
||||||
class Quiz(ormar.Model):
|
class Quiz(ormar.Model):
|
||||||
id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4(), nullable=False, unique=True)
|
id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4(), nullable=False, unique=True)
|
||||||
@@ -190,15 +179,6 @@ class Quiz(ormar.Model):
|
|||||||
background_image: str | None = ormar.Text(nullable=True, unique=False)
|
background_image: str | None = ormar.Text(nullable=True, unique=False)
|
||||||
kahoot_id: uuid.UUID | None = ormar.UUID(nullable=True, default=None)
|
kahoot_id: uuid.UUID | None = ormar.UUID(nullable=True, default=None)
|
||||||
|
|
||||||
@validator("background_image")
|
|
||||||
def must_come_from_local_cdn(cls, v):
|
|
||||||
if v is None:
|
|
||||||
return v
|
|
||||||
elif bool(re.match(server_regex, v)):
|
|
||||||
return v
|
|
||||||
else:
|
|
||||||
raise ValueError("does not match url scheme")
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
tablename = "quiz"
|
tablename = "quiz"
|
||||||
metadata = metadata
|
metadata = metadata
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ async def get_share(uuid: UUID) -> QuizTivity:
|
|||||||
share = await QuizTivityShare.objects.select_related("quiztivity").get_or_none(id=uuid)
|
share = await QuizTivityShare.objects.select_related("quiztivity").get_or_none(id=uuid)
|
||||||
if share is None:
|
if share is None:
|
||||||
raise HTTPException(status_code=404, detail="Share not found")
|
raise HTTPException(status_code=404, detail="Share not found")
|
||||||
print(share.quiztivity)
|
|
||||||
if share.expire_at is None:
|
if share.expire_at is None:
|
||||||
return share.quiztivity
|
return share.quiztivity
|
||||||
if share.expire_at < datetime.now():
|
if share.expire_at < datetime.now():
|
||||||
|
|||||||
@@ -12,11 +12,6 @@ import aiofiles.os
|
|||||||
_DEFAULT_CHUNK_SIZE = 32768 # bytes; arbitrary
|
_DEFAULT_CHUNK_SIZE = 32768 # bytes; arbitrary
|
||||||
|
|
||||||
|
|
||||||
async def aioshutil_copyfileobj(async_fsrc, async_fdst, *, chunksize: int = _DEFAULT_CHUNK_SIZE) -> None:
|
|
||||||
while (chunk := await async_fsrc.read(chunksize)) != b"":
|
|
||||||
await async_fdst.write(chunk)
|
|
||||||
|
|
||||||
|
|
||||||
class LocalStorage:
|
class LocalStorage:
|
||||||
def __init__(self, base_path: str):
|
def __init__(self, base_path: str):
|
||||||
self.base_path = base_path
|
self.base_path = base_path
|
||||||
|
|||||||
@@ -134,8 +134,9 @@ class S3Storage:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def size(self, file_name: str) -> int | None:
|
def size(self, file_name: str) -> int | None:
|
||||||
|
try:
|
||||||
res = self.client.stat_object(bucket_name=self.bucket_name, object_name=file_name)
|
res = self.client.stat_object(bucket_name=self.bucket_name, object_name=file_name)
|
||||||
if res is None:
|
except minio.error.S3Error:
|
||||||
return None
|
return None
|
||||||
return res.size
|
return res.size
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ class ValueStorage:
|
|||||||
image_id = None
|
image_id = None
|
||||||
cookies = None
|
cookies = None
|
||||||
file_id = None
|
file_id = None
|
||||||
|
quiztivity_id = None
|
||||||
|
share_id = None
|
||||||
|
expired_share_id = None
|
||||||
|
|
||||||
|
|
||||||
example_quiz = {
|
example_quiz = {
|
||||||
@@ -64,6 +67,19 @@ example_quiz = {
|
|||||||
test_user_email = "sth@byom.de"
|
test_user_email = "sth@byom.de"
|
||||||
test_user_password = "test"
|
test_user_password = "test"
|
||||||
|
|
||||||
|
example_quiztivity = {
|
||||||
|
"title": "Some test Quiztivity",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"title": "Some test question",
|
||||||
|
"type": "ABCD",
|
||||||
|
"data": {
|
||||||
|
"question": "Is ClassQuiz cool?",
|
||||||
|
"answers": [{"correct": True, "answer": "Yes"}, {"correct": False, "answer": "No"}],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
# mock_test_results = {'0': [{'username': 'Player 1', 'answer': 'Byte, Bit, KB, MB, GB, TB', 'right': False},
|
# mock_test_results = {'0': [{'username': 'Player 1', 'answer': 'Byte, Bit, KB, MB, GB, TB', 'right': False},
|
||||||
# {'username': 'Player 2', 'answer': 'Byte, Bit, KB, MB, GB, TB', 'right': False}, {'username': 'Player 3',
|
# {'username': 'Player 2', 'answer': 'Byte, Bit, KB, MB, GB, TB', 'right': False}, {'username': 'Player 3',
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import uuid
|
|||||||
import pytest
|
import pytest
|
||||||
from redis import Redis
|
from redis import Redis
|
||||||
from classquiz.config import settings
|
from classquiz.config import settings
|
||||||
from classquiz.tests import test_user_email, test_user_password
|
from classquiz.tests import test_user_email, test_user_password, example_quiztivity
|
||||||
from classquiz.tests import test_client, example_quiz, ValueStorage # noqa : F401
|
from classquiz.tests import test_client, example_quiz, ValueStorage # noqa : F401
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
@@ -508,6 +508,176 @@ class TestStorage:
|
|||||||
assert data["used"] == 0
|
assert data["used"] == 0
|
||||||
|
|
||||||
|
|
||||||
|
class TestQuizivity:
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_create_quiztivity(self, test_client: TestClient): # noqa : F811
|
||||||
|
resp = test_client.post("/api/v1/quiztivity/create", cookies=ValueStorage.cookies, json=example_quiztivity)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
ValueStorage.quiztivity_id = data["id"]
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_quiztivity(self, test_client: TestClient): # noqa : F811
|
||||||
|
resp = test_client.get("/api/v1/quiztivity/8bd77201-65ed-46fe-9160-cfe71dad501f", cookies=ValueStorage.cookies)
|
||||||
|
assert resp.status_code == 404
|
||||||
|
resp = test_client.get(f"/api/v1/quiztivity/{ValueStorage.quiztivity_id}", cookies=ValueStorage.cookies)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert data["id"] == ValueStorage.quiztivity_id
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_put_quiztivity(self, test_client: TestClient): # noqa : F811
|
||||||
|
example_quiztivity["title"] = "New title"
|
||||||
|
resp = test_client.put(
|
||||||
|
f"/api/v1/quiztivity/{ValueStorage.quiztivity_id}", json=example_quiztivity, cookies=ValueStorage.cookies
|
||||||
|
)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
resp = test_client.put(
|
||||||
|
"/api/v1/quiztivity/8bd77201-65ed-46fe-9160-cfe71dad501f",
|
||||||
|
json=example_quiztivity,
|
||||||
|
cookies=ValueStorage.cookies,
|
||||||
|
)
|
||||||
|
assert resp.status_code == 404
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_all_quiztivities(self, test_client: TestClient): # noqa : F811
|
||||||
|
resp = test_client.get("/api/v1/quiztivity/", cookies=ValueStorage.cookies)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert type(data) is list
|
||||||
|
assert data[0]["id"] == ValueStorage.quiztivity_id
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_create_share(self, test_client: TestClient): # noqa : F811
|
||||||
|
resp = test_client.post(
|
||||||
|
"/api/v1/quiztivity/shares/",
|
||||||
|
cookies=ValueStorage.cookies,
|
||||||
|
json={"quiztivity": ValueStorage.quiztivity_id, "expire_in": None},
|
||||||
|
)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
ValueStorage.share_id = data["id"]
|
||||||
|
resp = test_client.post(
|
||||||
|
"/api/v1/quiztivity/shares/",
|
||||||
|
cookies=ValueStorage.cookies,
|
||||||
|
json={"quiztivity": "a090077f-9059-42bc-9783-f2cd01e069b8", "expire_in": None},
|
||||||
|
)
|
||||||
|
assert resp.status_code == 400
|
||||||
|
resp = test_client.post(
|
||||||
|
"/api/v1/quiztivity/shares/",
|
||||||
|
cookies=ValueStorage.cookies,
|
||||||
|
json={"quiztivity": ValueStorage.quiztivity_id, "expire_in": 0},
|
||||||
|
)
|
||||||
|
data = resp.json()
|
||||||
|
ValueStorage.expired_share_id = data["id"]
|
||||||
|
assert resp.status_code == 200
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_share(self, test_client: TestClient): # noqa : F811
|
||||||
|
resp = test_client.get(
|
||||||
|
"/api/v1/quiztivity/shares/8bd77201-65ed-46fe-9160-cfe71dad501f", cookies=ValueStorage.cookies
|
||||||
|
)
|
||||||
|
assert resp.status_code == 404
|
||||||
|
resp = test_client.get(f"/api/v1/quiztivity/shares/{ValueStorage.share_id}", cookies=ValueStorage.cookies)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert data["id"] == ValueStorage.quiztivity_id
|
||||||
|
resp = test_client.get(
|
||||||
|
f"/api/v1/quiztivity/shares/{ValueStorage.expired_share_id}", cookies=ValueStorage.cookies
|
||||||
|
)
|
||||||
|
assert resp.status_code == 410
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_update_share(self, test_client: TestClient): # noqa : F811
|
||||||
|
resp = test_client.put(
|
||||||
|
"/api/v1/quiztivity/shares/8bd77201-65ed-46fe-9160-cfe71dad501f",
|
||||||
|
cookies=ValueStorage.cookies,
|
||||||
|
json={"expire_in": 50},
|
||||||
|
)
|
||||||
|
assert resp.status_code == 404
|
||||||
|
resp = test_client.put(
|
||||||
|
f"/api/v1/quiztivity/shares/{ValueStorage.share_id}", cookies=ValueStorage.cookies, json={"expire_in": 50}
|
||||||
|
)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
|
||||||
|
async def test_delete_share(self, test_client: TestClient): # noqa : F811
|
||||||
|
resp = test_client.delete(
|
||||||
|
"/api/v1/quiztivity/shares/8bd77201-65ed-46fe-9160-cfe71dad501f", cookies=ValueStorage.cookies
|
||||||
|
)
|
||||||
|
assert resp.status_code == 404
|
||||||
|
resp = test_client.delete(
|
||||||
|
f"/api/v1/quiztivity/shares/{ValueStorage.expired_share_id}", cookies=ValueStorage.cookies
|
||||||
|
)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_shares(self, test_client: TestClient): # noqa : F811
|
||||||
|
resp = test_client.get("/api/v1/quiztivity/shares/", cookies=ValueStorage.cookies)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert type(data) is list
|
||||||
|
assert data[0]["id"] == ValueStorage.share_id
|
||||||
|
assert data[0]["expire_in"] == 49
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_shares_by_quiztivity(self, test_client: TestClient): # noqa : F811
|
||||||
|
resp = test_client.get(f"/api/v1/quiztivity/{ValueStorage.quiztivity_id}/shares", cookies=ValueStorage.cookies)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert type(data) is list
|
||||||
|
assert data[0]["id"] == ValueStorage.share_id
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_shares(self, test_client: TestClient): # noqa : F811
|
||||||
|
resp = test_client.get("/api/v1/quiztivity/shares/", cookies=ValueStorage.cookies)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert type(data) is list
|
||||||
|
assert data[0]["id"] == ValueStorage.share_id
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_delete_quiztivity(self, test_client: TestClient): # noqa : F811
|
||||||
|
test_client.delete(f"/api/v1/quiztivity/shares/{ValueStorage.share_id}", cookies=ValueStorage.cookies)
|
||||||
|
resp = test_client.delete(
|
||||||
|
"/api/v1/quiztivity/8bd77201-65ed-46fe-9160-cfe71dad501f", cookies=ValueStorage.cookies
|
||||||
|
)
|
||||||
|
assert resp.status_code == 404
|
||||||
|
resp = test_client.delete(f"/api/v1/quiztivity/{ValueStorage.quiztivity_id}", cookies=ValueStorage.cookies)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
class TestAvatar:
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_customized_avatar(self, test_client: TestClient): # noqa : F811
|
||||||
|
resp = test_client.get("/api/v1/avatar/custom?skin_color=69", cookies=ValueStorage.cookies)
|
||||||
|
assert resp.status_code == 400
|
||||||
|
resp = test_client.get("/api/v1/avatar/custom", cookies=ValueStorage.cookies)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
assert "image/svg+xml" in resp.headers.get("Content-Type")
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_save_avatar(self, test_client: TestClient): # noqa : F811
|
||||||
|
resp = test_client.post("/api/v1/avatar/save?skin_color=69", cookies=ValueStorage.cookies)
|
||||||
|
assert resp.status_code == 400
|
||||||
|
resp = test_client.post("/api/v1/avatar/save", cookies=ValueStorage.cookies)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_own_avatar(self, test_client: TestClient): # noqa : F811
|
||||||
|
resp = test_client.get("/api/v1/users/avatar", cookies=ValueStorage.cookies)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_other_avatar(self, test_client: TestClient): # noqa : F811
|
||||||
|
resp = test_client.get(
|
||||||
|
"/api/v1/users/8bd77201-65ed-46fe-9160-cfe71dad501f/avatar", cookies=ValueStorage.cookies
|
||||||
|
)
|
||||||
|
assert resp.status_code == 404
|
||||||
|
user_id = test_client.get("/api/v1/users/me", cookies=ValueStorage.cookies).json()["id"]
|
||||||
|
resp = test_client.get(f"/api/v1/users/avatar/{user_id}", cookies=ValueStorage.cookies)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
class TestExImport:
|
class TestExImport:
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_export_quiz(self, test_client: TestClient): # noqa : F811
|
async def test_export_quiz(self, test_client: TestClient): # noqa : F811
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ async def storage_tester(storage: Storage):
|
|||||||
res = storage.download(file_name="test.txt")
|
res = storage.download(file_name="test.txt")
|
||||||
async for chunk in res:
|
async for chunk in res:
|
||||||
assert bytes(chunk) == file_contents
|
assert bytes(chunk) == file_contents
|
||||||
|
res = await storage.get_file_size(file_name="test.txt")
|
||||||
|
assert res == len(file_contents)
|
||||||
|
res = await storage.get_file_size(file_name="asdsadasdasdadfdsf.txt")
|
||||||
|
assert res is None
|
||||||
res = await storage.delete(file_names=["test.txt"])
|
res = await storage.delete(file_names=["test.txt"])
|
||||||
assert res is None
|
assert res is None
|
||||||
res = storage.download(file_name="test.txt")
|
res = storage.download(file_name="test.txt")
|
||||||
|
|||||||
Reference in New Issue
Block a user