More refactoring
This commit is contained in:
@@ -53,7 +53,6 @@ def get_highest_high_scores(
|
||||
.first()
|
||||
)
|
||||
if high_score:
|
||||
print(str(high_score.time))
|
||||
return [
|
||||
Score(
|
||||
score_value=high_score.score_value,
|
||||
|
||||
@@ -6,10 +6,33 @@ from src.models import CourseProgress, LearnableProgress, User
|
||||
from src.schemas.learnableprogress import SavedLearnableProgress
|
||||
|
||||
|
||||
def get_learnables(db: Session, user: User, course: CourseEnum):
|
||||
"""Get all learnables of a certain course"""
|
||||
db_course = (
|
||||
db.query(CourseProgress)
|
||||
.filter(
|
||||
CourseProgress.owner_id == user.user_id, CourseProgress.course == course
|
||||
)
|
||||
.first()
|
||||
)
|
||||
db_learnable_query = (
|
||||
db.query(LearnableProgress)
|
||||
.filter(LearnableProgress.course_progress_id == db_course.course_progress_id)
|
||||
.all()
|
||||
)
|
||||
|
||||
return [
|
||||
SavedLearnableProgress(
|
||||
index=dbl.index, in_use=dbl.in_use, name=dbl.name, progress=dbl.progress
|
||||
)
|
||||
for dbl in db_learnable_query
|
||||
]
|
||||
|
||||
|
||||
def create_learnable(
|
||||
db: Session, user: User, course: CourseEnum, learnable: SavedLearnableProgress
|
||||
):
|
||||
"""Create a new learnable"""
|
||||
"""Create a new learnable for a given course"""
|
||||
if learnable.index < 0:
|
||||
raise HTTPException(status_code=400, detail="Negative index not allowed")
|
||||
|
||||
|
||||
13
src/main.py
13
src/main.py
@@ -128,6 +128,19 @@ async def patch_course_progress(
|
||||
)
|
||||
|
||||
|
||||
@app.get(
|
||||
"/learnables/{course}",
|
||||
response_model=List[learnableprogress.SavedLearnableProgress],
|
||||
)
|
||||
async def create_learnable(
|
||||
course: CourseEnum,
|
||||
current_user_name: str = Depends(crud_authentication.get_current_user_name),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
current_user = crud_users.get_user_by_username(db, current_user_name)
|
||||
return crud_learnables.get_learnables(db, current_user, course)
|
||||
|
||||
|
||||
@app.post("/learnables/{course}")
|
||||
async def create_learnable(
|
||||
course: CourseEnum,
|
||||
|
||||
@@ -16,10 +16,17 @@ password = "password"
|
||||
avatar_index = 1
|
||||
|
||||
|
||||
def get_headers(token=None):
|
||||
if token:
|
||||
return {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
else:
|
||||
return {"Content-Type": "application/json"}
|
||||
|
||||
|
||||
async def register_user():
|
||||
response = client.post(
|
||||
"/register",
|
||||
headers={"Content-Type": "application/json"},
|
||||
headers=get_headers(),
|
||||
json={"username": username, "password": password, "avatar_index": avatar_index},
|
||||
)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
from src.database import Base
|
||||
from src.models import CourseProgress, HighScore, User
|
||||
from src.models import CourseProgress, HighScore, LearnableProgress, User
|
||||
|
||||
SQLALCHEMY_DATABASE_URL = "postgresql://admin:WeSign123!@localhost/wesigntest"
|
||||
|
||||
@@ -17,6 +17,7 @@ def clear_db():
|
||||
db = TestSessionLocal()
|
||||
|
||||
db.query(HighScore).delete()
|
||||
db.query(LearnableProgress).delete()
|
||||
db.query(CourseProgress).delete()
|
||||
db.query(User).delete()
|
||||
db.commit()
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import pytest
|
||||
|
||||
from tests.base import avatar_index, client, password, register_user, username
|
||||
from tests.base import (avatar_index, client, get_headers, password,
|
||||
register_user, username)
|
||||
from tests.config.database import clear_db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_register():
|
||||
async def test_register_should_succeed():
|
||||
"""Test the register endpoint"""
|
||||
clear_db()
|
||||
|
||||
response = client.post(
|
||||
"/register",
|
||||
headers={"Content-Type": "application/json"},
|
||||
headers=get_headers(),
|
||||
json={"username": username, "password": password, "avatar_index": avatar_index},
|
||||
)
|
||||
|
||||
@@ -27,7 +28,7 @@ async def test_register_duplicate_name_should_fail():
|
||||
|
||||
response = client.post(
|
||||
"/register",
|
||||
headers={"Content-Type": "application/json"},
|
||||
headers=get_headers(),
|
||||
json={"username": username, "password": password, "avatar_index": avatar_index},
|
||||
)
|
||||
|
||||
@@ -42,7 +43,7 @@ async def test_register_without_username_should_fail():
|
||||
|
||||
response = client.post(
|
||||
"/register",
|
||||
headers={"Content-Type": "application/json"},
|
||||
headers=get_headers(),
|
||||
json={"password": password, "avatar_index": avatar_index},
|
||||
)
|
||||
|
||||
@@ -57,7 +58,7 @@ async def test_register_without_password_should_fail():
|
||||
|
||||
response = client.post(
|
||||
"/register",
|
||||
headers={"Content-Type": "application/json"},
|
||||
headers=get_headers(),
|
||||
json={"username": username, "avatar_index": avatar_index},
|
||||
)
|
||||
|
||||
@@ -72,7 +73,7 @@ async def test_register_without_avatar_should_fail():
|
||||
|
||||
response = client.post(
|
||||
"/register",
|
||||
headers={"Content-Type": "application/json"},
|
||||
headers=get_headers(),
|
||||
json={"username": username, "password": password},
|
||||
)
|
||||
|
||||
@@ -81,14 +82,14 @@ async def test_register_without_avatar_should_fail():
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_login():
|
||||
async def test_login_should_succeed():
|
||||
"""Test the login endpoint"""
|
||||
clear_db()
|
||||
await register_user()
|
||||
|
||||
response = client.post(
|
||||
"/login",
|
||||
headers={"Content-Type": "application/json"},
|
||||
headers=get_headers(),
|
||||
json={"username": username, "password": password},
|
||||
)
|
||||
|
||||
@@ -104,7 +105,7 @@ async def test_login_wrong_password_should_fail():
|
||||
wrong_password = password + "extra characters"
|
||||
response = client.post(
|
||||
"/login",
|
||||
headers={"Content-Type": "application/json"},
|
||||
headers=get_headers(),
|
||||
json={"username": username, "password": wrong_password},
|
||||
)
|
||||
|
||||
@@ -120,7 +121,7 @@ async def test_login_without_username_should_fail():
|
||||
|
||||
response = client.post(
|
||||
"/login",
|
||||
headers={"Content-Type": "application/json"},
|
||||
headers=get_headers(),
|
||||
json={"password": password},
|
||||
)
|
||||
|
||||
@@ -136,7 +137,7 @@ async def test_login_without_password_should_fail():
|
||||
|
||||
response = client.post(
|
||||
"/login",
|
||||
headers={"Content-Type": "application/json"},
|
||||
headers=get_headers(),
|
||||
json={"username": username},
|
||||
)
|
||||
|
||||
|
||||
@@ -3,17 +3,17 @@ import random
|
||||
import pytest
|
||||
|
||||
from src.enums import CourseEnum
|
||||
from tests.base import client, register_user
|
||||
from tests.base import client, get_headers, register_user
|
||||
from tests.config.database import clear_db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_register_creates_progress_of_zero():
|
||||
async def test_register_should_create_progress_of_zero():
|
||||
"""Test whether registering a new user initializes all progress values to 0.0"""
|
||||
clear_db()
|
||||
|
||||
token = await register_user()
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
for course in CourseEnum:
|
||||
if course != CourseEnum.All:
|
||||
@@ -27,12 +27,12 @@ async def test_register_creates_progress_of_zero():
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_all_returns_all():
|
||||
async def test_get_all_sould_return_all():
|
||||
"""Test whether the 'All'-course fetches all course progress values"""
|
||||
clear_db()
|
||||
token = await register_user()
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
response = client.get("/courseprogress/All", headers=headers)
|
||||
|
||||
assert response.status_code == 200
|
||||
@@ -48,7 +48,7 @@ async def test_get_course_progress_without_auth_should_fail():
|
||||
"""Test whether fetching a course progress value without authentication fails"""
|
||||
clear_db()
|
||||
|
||||
headers = {"Content-Type": "application/json"}
|
||||
headers = get_headers()
|
||||
|
||||
for course in CourseEnum:
|
||||
response = client.get(f"/courseprogress/{course}", headers=headers)
|
||||
@@ -64,19 +64,19 @@ async def test_get_nonexisting_course_should_fail():
|
||||
|
||||
fake_course = "FakeCourse"
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
response = client.get(f"/courseprogress/{fake_course}", headers=headers)
|
||||
|
||||
assert response.status_code == 422
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_patch_course_progress():
|
||||
async def test_patch_course_progress_should_succeed():
|
||||
"""Test whether patching the progress value of a course works properly"""
|
||||
clear_db()
|
||||
token = await register_user()
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
for course in CourseEnum:
|
||||
if course != CourseEnum.All:
|
||||
@@ -98,7 +98,7 @@ async def test_patch_all_should_patch_all_courses():
|
||||
clear_db()
|
||||
token = await register_user()
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
progress = random.uniform(0, 1)
|
||||
|
||||
@@ -128,7 +128,7 @@ async def test_patch_nonexisting_course_should_fail():
|
||||
|
||||
fake_course = "FakeCourse"
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
progress = random.uniform(0, 1)
|
||||
|
||||
@@ -147,7 +147,7 @@ async def test_patch_course_with_invalid_value_should_fail():
|
||||
clear_db()
|
||||
token = await register_user()
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
too_high_progress = random.uniform(0, 1) + 2
|
||||
too_low_progress = random.uniform(0, 1) - 2
|
||||
@@ -174,7 +174,7 @@ async def test_patch_course_progress_without_auth_should_fail():
|
||||
"""Test whether updating a course progress value without authentication fails"""
|
||||
clear_db()
|
||||
|
||||
headers = {"Content-Type": "application/json"}
|
||||
headers = get_headers()
|
||||
|
||||
for course in CourseEnum:
|
||||
response = client.patch(
|
||||
|
||||
@@ -3,17 +3,18 @@ import random
|
||||
import pytest
|
||||
|
||||
from src.enums import MinigameEnum
|
||||
from tests.base import avatar_index, client, password, register_user
|
||||
from tests.base import (avatar_index, client, get_headers, password,
|
||||
register_user)
|
||||
from tests.config.database import clear_db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_put_highscore():
|
||||
async def test_put_highscore_should_succeed():
|
||||
"""Test whether putting a new high score succeeds"""
|
||||
clear_db()
|
||||
token = await register_user()
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
for minigame in MinigameEnum:
|
||||
score_value = random.random()
|
||||
@@ -31,12 +32,12 @@ async def test_put_highscore():
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_put_lower_highscore_does_not_change_old_value():
|
||||
async def test_put_lower_highscore_should_not_change_old_value():
|
||||
"""Test whether putting a new high score lower than the current one doesn't change the old one"""
|
||||
clear_db()
|
||||
token = await register_user()
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
for minigame in MinigameEnum:
|
||||
score_value = random.random()
|
||||
@@ -74,7 +75,7 @@ async def test_put_highscore_for_nonexisting_minigame_should_fail():
|
||||
|
||||
fake_minigame = "FakeGame"
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
response = client.put(
|
||||
f"/highscores/{fake_minigame}",
|
||||
@@ -90,7 +91,7 @@ async def test_put_highscores_without_auth_should_fail():
|
||||
"""Test whether putting high scores without authentication fails"""
|
||||
clear_db()
|
||||
|
||||
headers = {"Content-Type": "application/json"}
|
||||
headers = get_headers()
|
||||
|
||||
for minigame in MinigameEnum:
|
||||
response = client.put(
|
||||
@@ -107,7 +108,7 @@ async def test_get_highscores_without_auth_should_fail():
|
||||
"""Test whether fetching high scores without authentication fails"""
|
||||
clear_db()
|
||||
|
||||
headers = {"Content-Type": "application/json"}
|
||||
headers = get_headers()
|
||||
|
||||
for minigame in MinigameEnum:
|
||||
response = client.get(
|
||||
@@ -133,7 +134,7 @@ async def test_get_highscore_for_nonexisting_minigame_should_fail():
|
||||
|
||||
fake_minigame = "FakeGame"
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
response = client.get(
|
||||
f"/highscores/{fake_minigame}",
|
||||
@@ -156,7 +157,7 @@ async def test_get_invalid_number_of_highscores_should_fail():
|
||||
clear_db()
|
||||
token = await register_user()
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
for minigame in MinigameEnum:
|
||||
response = client.get(
|
||||
@@ -168,12 +169,12 @@ async def test_get_invalid_number_of_highscores_should_fail():
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_highscores_should_work_with_default_value():
|
||||
async def test_get_highscores_should_succeed_with_default_value():
|
||||
"""Test whether fetching high scores without passing an explicit amount still succeeds"""
|
||||
clear_db()
|
||||
token = await register_user()
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
for minigame in MinigameEnum:
|
||||
response = client.get(
|
||||
@@ -185,16 +186,16 @@ async def test_get_highscores_should_work_with_default_value():
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_highscores_returns_sorted_list_with_correct_length():
|
||||
async def test_get_highscores_should_return_sorted_list_with_correct_length():
|
||||
"""Test whether getting a list of high scores gets a list in descending order and of the correct length"""
|
||||
clear_db()
|
||||
token = await register_user()
|
||||
|
||||
headers = {"Content-Type": "application/json"}
|
||||
headers = get_headers()
|
||||
|
||||
for minigame in MinigameEnum:
|
||||
clear_db()
|
||||
nr_entries = random.randint(5, 50)
|
||||
nr_entries = random.randint(5, 10)
|
||||
token = ""
|
||||
|
||||
users_score_tuples = [
|
||||
@@ -218,10 +219,7 @@ async def test_get_highscores_returns_sorted_list_with_correct_length():
|
||||
|
||||
response = client.put(
|
||||
f"/highscores/{minigame}",
|
||||
headers={
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
headers=get_headers(token),
|
||||
json={"score_value": score},
|
||||
)
|
||||
|
||||
@@ -229,10 +227,7 @@ async def test_get_highscores_returns_sorted_list_with_correct_length():
|
||||
|
||||
response = client.get(
|
||||
f"/highscores/{minigame}?mine_only=false&amount={int(nr_entries)}",
|
||||
headers={
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
headers=get_headers(token),
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
@@ -243,14 +238,27 @@ async def test_get_highscores_returns_sorted_list_with_correct_length():
|
||||
for i in range(1, len(response)):
|
||||
assert response[i]["score_value"] <= response[i - 1]["score_value"]
|
||||
|
||||
response = client.get(
|
||||
f"/highscores/{minigame}?most_recent=true&mine_only=false&amount={int(nr_entries)}",
|
||||
headers=get_headers(token),
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
response = response.json()
|
||||
|
||||
assert len(response) == nr_entries
|
||||
|
||||
for i in range(1, len(response)):
|
||||
assert response[i]["time"] <= response[i - 1]["time"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_own_existing_high_score_should_return_high_score():
|
||||
async def test_get_own_existing_high_score_should_succeed():
|
||||
"""Test whether fetching your own high score of a game succeeds"""
|
||||
clear_db()
|
||||
token = await register_user()
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
for minigame in MinigameEnum:
|
||||
response = client.put(
|
||||
@@ -276,7 +284,7 @@ async def test_get_own_nonexisting_high_score_should_return_empty_list():
|
||||
clear_db()
|
||||
token = await register_user()
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
for minigame in MinigameEnum:
|
||||
response = client.get(
|
||||
@@ -294,7 +302,7 @@ async def test_get_multiple_own_high_scores_of_same_game_should_fail():
|
||||
clear_db()
|
||||
token = await register_user()
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
for minigame in MinigameEnum:
|
||||
response = client.get(
|
||||
|
||||
39
tests/test_learnables.py
Normal file
39
tests/test_learnables.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import random
|
||||
|
||||
import pytest
|
||||
|
||||
from src.enums import CourseEnum
|
||||
from tests.base import client, get_headers, register_user
|
||||
from tests.config.database import clear_db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_learnables_should_succeed():
|
||||
clear_db()
|
||||
token = await register_user()
|
||||
|
||||
headers = get_headers(token)
|
||||
|
||||
for course in CourseEnum:
|
||||
if course != CourseEnum.All:
|
||||
nr_learnables = random.randint(1, 5)
|
||||
for i in range(nr_learnables):
|
||||
response = client.post(
|
||||
f"/learnables/{course}",
|
||||
json={
|
||||
"index": i,
|
||||
"in_use": bool(random.randint(0, 1)),
|
||||
"name": f"{course} {i}",
|
||||
},
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
response = client.get(f"/learnables/{course}", headers=headers)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
response = response.json()
|
||||
|
||||
assert len(response) == nr_learnables
|
||||
@@ -1,6 +1,7 @@
|
||||
import pytest
|
||||
|
||||
from tests.base import avatar_index, client, register_user, username
|
||||
from tests.base import (avatar_index, client, get_headers, register_user,
|
||||
username)
|
||||
from tests.config.database import clear_db
|
||||
|
||||
patched_username = "New name"
|
||||
@@ -9,13 +10,13 @@ patched_avatar_index = 2
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_patch_user():
|
||||
async def test_patch_user_should_succeed():
|
||||
"""Test the patching of a user's username, password and avatar"""
|
||||
clear_db()
|
||||
|
||||
token = await register_user()
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
response = client.patch(
|
||||
"/users",
|
||||
@@ -30,14 +31,14 @@ async def test_patch_user():
|
||||
|
||||
response = client.post(
|
||||
"/login",
|
||||
headers={"Content-Type": "application/json"},
|
||||
headers=get_headers(),
|
||||
json={"username": patched_username, "password": patched_password},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
token = response.json()["access_token"]
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
response = client.get("/saveddata", headers=headers)
|
||||
assert response.status_code == 200
|
||||
@@ -47,13 +48,13 @@ async def test_patch_user():
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_patch_user_with_empty_fields():
|
||||
"""Patching a user with empty fields should fail"""
|
||||
async def test_patch_user_with_empty_fields_should_succeed():
|
||||
"""Patching a user with empty fields should still succeed"""
|
||||
clear_db()
|
||||
|
||||
token = await register_user()
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
headers = get_headers(token)
|
||||
|
||||
response = client.patch(
|
||||
"/users",
|
||||
|
||||
Reference in New Issue
Block a user