feat(api+testing): select member by email
- Reorganized folder structure so routes live in the same folder - Set up pytest fixtures for future use
This commit is contained in:
parent
b64030617c
commit
49c83fa287
@ -46,6 +46,10 @@ target-version = ["py311"]
|
||||
addopts = "--showlocals"
|
||||
asyncio_mode = "auto"
|
||||
pythonpath = ["src"]
|
||||
filterwarnings = [
|
||||
"error",
|
||||
'ignore::DeprecationWarning',
|
||||
]
|
||||
|
||||
[tool.pdm.scripts]
|
||||
|
||||
|
@ -4,8 +4,7 @@ import redis.asyncio as redis
|
||||
from fastapi import FastAPI
|
||||
from fastapi_limiter import FastAPILimiter
|
||||
|
||||
from src.neo_neo_todo.control import control
|
||||
from src.neo_neo_todo.sessions import sessions
|
||||
from src.neo_neo_todo.routes import control, sessions
|
||||
from src.neo_neo_todo.utils.database import pool
|
||||
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
|
||||
from psycopg import sql
|
||||
from psycopg.rows import class_row
|
||||
from psycopg_pool import AsyncConnectionPool
|
||||
|
||||
|
||||
@dataclass
|
||||
class Member:
|
||||
@ -9,3 +13,26 @@ class Member:
|
||||
password_hash: str
|
||||
created: datetime
|
||||
email_verified: datetime | None
|
||||
|
||||
|
||||
async def select_member_by_email(db: AsyncConnectionPool, email: str) -> Member | None:
|
||||
"""
|
||||
Find exactly one email match in users list in PostgreSQL database
|
||||
"""
|
||||
async with db.connection() as conn:
|
||||
async with conn.cursor(row_factory=class_row(Member)) as curr:
|
||||
query = sql.SQL(
|
||||
"""
|
||||
SELECT id, email, password_hash, created, email_verified
|
||||
FROM members
|
||||
WHERE LOWER(email) = LOWER(%s);
|
||||
"""
|
||||
)
|
||||
|
||||
await curr.execute(query, (email,))
|
||||
|
||||
print(query.as_string(conn))
|
||||
|
||||
member = await curr.fetchone()
|
||||
|
||||
return None if member is None else member
|
||||
|
@ -1,5 +1,4 @@
|
||||
from fastapi import APIRouter
|
||||
from starlette.requests import Request
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/control",
|
||||
@ -8,5 +7,5 @@ router = APIRouter(
|
||||
|
||||
|
||||
@router.get("/ping")
|
||||
async def ping(request: Request):
|
||||
async def ping():
|
||||
return {"ping": "pong"}
|
@ -1,6 +1,5 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi_limiter.depends import RateLimiter
|
||||
from starlette.requests import Request
|
||||
|
||||
from src.neo_neo_todo.models.session import LoginData
|
||||
|
||||
@ -11,7 +10,7 @@ router = APIRouter(
|
||||
|
||||
|
||||
@router.post("", dependencies=[Depends(RateLimiter(times=100, seconds=600))])
|
||||
async def login(request: Request, login_data: LoginData):
|
||||
async def login(login_data: LoginData):
|
||||
"""
|
||||
Login to the todo app
|
||||
|
28
backend/tests/conftest.py
Normal file
28
backend/tests/conftest.py
Normal file
@ -0,0 +1,28 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
from psycopg_pool import AsyncConnectionPool
|
||||
|
||||
from src.neo_neo_todo.main import app
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def client():
|
||||
yield TestClient(app)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def db_pool():
|
||||
try:
|
||||
postgres_db_url = os.environ["TODO_DB_DATABASE_URL"]
|
||||
except KeyError:
|
||||
raise KeyError("Can't find postgres DB URL")
|
||||
|
||||
pool = AsyncConnectionPool(postgres_db_url, open=False)
|
||||
|
||||
await pool.open()
|
||||
|
||||
yield pool
|
||||
|
||||
await pool.close()
|
@ -1,12 +1,7 @@
|
||||
import pytest
|
||||
from httpx import AsyncClient
|
||||
|
||||
from src.neo_neo_todo.main import app
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_ping():
|
||||
async with AsyncClient(app=app, base_url="http://test") as ac:
|
||||
response = await ac.get("/control/ping")
|
||||
async def test_ping(client: TestClient):
|
||||
response = client.get("/control/ping")
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"ping": "pong"}
|
||||
|
7
backend/tests/test_model_member.py
Normal file
7
backend/tests/test_model_member.py
Normal file
@ -0,0 +1,7 @@
|
||||
from src.neo_neo_todo.models.member import select_member_by_email
|
||||
|
||||
|
||||
async def test_model_member(db_pool):
|
||||
member = await select_member_by_email(db_pool, "member@todo.test")
|
||||
assert member is not None
|
||||
assert member.email == "member@todo.test"
|
Loading…
x
Reference in New Issue
Block a user