182 lines
5.5 KiB
Python
182 lines
5.5 KiB
Python
import os
|
|
|
|
from tests.conftest import client, get_admin_token, get_invite_token, ADMIN_PASSWORD
|
|
|
|
|
|
# ── Auth tests ──
|
|
|
|
def test_login_success():
|
|
resp = client.post("/api/auth/login", json={"username": "admin", "password": ADMIN_PASSWORD})
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert "access_token" in data
|
|
assert data["user"]["username"] == "admin"
|
|
|
|
|
|
def test_login_wrong_password():
|
|
resp = client.post("/api/auth/login", json={"username": "admin", "password": "wrong"})
|
|
assert resp.status_code == 401
|
|
|
|
|
|
def test_login_wrong_username():
|
|
resp = client.post("/api/auth/login", json={"username": "nobody", "password": ADMIN_PASSWORD})
|
|
assert resp.status_code == 401
|
|
|
|
|
|
def test_me_unauthorized():
|
|
resp = client.get("/api/auth/me")
|
|
assert resp.status_code == 401
|
|
|
|
|
|
def test_me_authorized():
|
|
token = get_admin_token()
|
|
resp = client.get("/api/auth/me", headers={"Authorization": f"Bearer {token}"})
|
|
assert resp.status_code == 200
|
|
assert resp.json()["username"] == "admin"
|
|
|
|
|
|
# ── Invitation tests ──
|
|
|
|
def test_register_with_invite():
|
|
invite_token = get_invite_token()
|
|
resp = client.post("/api/auth/register", json={
|
|
"username": "newuser",
|
|
"email": "new@test.com",
|
|
"password": "NewPass123",
|
|
"invite_token": invite_token,
|
|
})
|
|
assert resp.status_code == 200
|
|
assert resp.json()["user"]["username"] == "newuser"
|
|
|
|
|
|
def test_register_invalid_invite():
|
|
resp = client.post("/api/auth/register", json={
|
|
"username": "user2",
|
|
"email": "u2@test.com",
|
|
"password": "Pass1234",
|
|
"invite_token": "invalid-token",
|
|
})
|
|
assert resp.status_code == 400
|
|
|
|
|
|
def test_invite_reuse():
|
|
invite_token = get_invite_token()
|
|
client.post("/api/auth/register", json={
|
|
"username": "reuse1",
|
|
"email": "r1@test.com",
|
|
"password": "Pass1234",
|
|
"invite_token": invite_token,
|
|
})
|
|
resp = client.post("/api/auth/register", json={
|
|
"username": "reuse2",
|
|
"email": "r2@test.com",
|
|
"password": "Pass1234",
|
|
"invite_token": invite_token,
|
|
})
|
|
# 400 = invitation déjà utilisée, 429 = rate limit (les deux empêchent la réutilisation)
|
|
assert resp.status_code in (400, 429)
|
|
|
|
|
|
# ── Drink CRUD tests ──
|
|
|
|
def test_create_drink():
|
|
token = get_admin_token()
|
|
resp = client.post("/api/drinks", json={
|
|
"name": "Château Test",
|
|
"category": "wine",
|
|
"rating": 4.5,
|
|
}, headers={"Authorization": f"Bearer {token}"})
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert data["name"] == "Château Test"
|
|
assert data["category"] == "wine"
|
|
|
|
|
|
def test_list_drinks():
|
|
token = get_admin_token()
|
|
resp = client.get("/api/drinks", headers={"Authorization": f"Bearer {token}"})
|
|
assert resp.status_code == 200
|
|
assert len(resp.json()) > 0
|
|
|
|
|
|
def test_update_drink():
|
|
token = get_admin_token()
|
|
create_resp = client.post("/api/drinks", json={
|
|
"name": "Château Test",
|
|
"category": "wine",
|
|
}, headers={"Authorization": f"Bearer {token}"})
|
|
drink_id = create_resp.json()["id"]
|
|
resp = client.put(f"/api/drinks/{drink_id}", json={
|
|
"name": "Château Updated",
|
|
"rating": 5.0,
|
|
}, headers={"Authorization": f"Bearer {token}"})
|
|
assert resp.status_code == 200
|
|
assert resp.json()["name"] == "Château Updated"
|
|
assert resp.json()["rating"] == 5.0
|
|
|
|
|
|
def test_delete_drink():
|
|
token = get_admin_token()
|
|
create_resp = client.post("/api/drinks", json={
|
|
"name": "Château Test",
|
|
"category": "wine",
|
|
}, headers={"Authorization": f"Bearer {token}"})
|
|
drink_id = create_resp.json()["id"]
|
|
resp = client.delete(f"/api/drinks/{drink_id}", headers={"Authorization": f"Bearer {token}"})
|
|
assert resp.status_code == 200
|
|
resp = client.get(f"/api/drinks/{drink_id}", headers={"Authorization": f"Bearer {token}"})
|
|
assert resp.status_code == 404
|
|
|
|
|
|
def test_drink_owner_isolation():
|
|
token = get_admin_token()
|
|
create_resp = client.post("/api/drinks", json={
|
|
"name": "Château Test",
|
|
"category": "wine",
|
|
}, headers={"Authorization": f"Bearer {token}"})
|
|
drink_id = create_resp.json()["id"]
|
|
|
|
from database import SessionLocal
|
|
from models import User
|
|
from auth import hash_password, create_access_token
|
|
|
|
db = SessionLocal()
|
|
try:
|
|
other = User(username="other", email="other@test.com", hashed_password=hash_password("Other123"))
|
|
db.add(other)
|
|
db.commit()
|
|
db.refresh(other)
|
|
other_token = create_access_token({"sub": str(other.id), "token_version": other.token_version})
|
|
finally:
|
|
db.close()
|
|
|
|
resp = client.get(f"/api/drinks/{drink_id}", headers={"Authorization": f"Bearer {other_token}"})
|
|
assert resp.status_code == 404
|
|
|
|
|
|
# ── Rate limiter test ──
|
|
|
|
def test_rate_limit_blocks():
|
|
for _ in range(6):
|
|
client.post("/api/auth/login", json={"username": "admin", "password": "wrong"})
|
|
resp = client.post("/api/auth/login", json={"username": "admin", "password": "wrong"})
|
|
assert resp.status_code == 429
|
|
|
|
|
|
# ── Logout test ──
|
|
|
|
def test_logout_invalidates_token():
|
|
token = get_admin_token()
|
|
resp = client.post("/api/auth/logout", headers={"Authorization": f"Bearer {token}"})
|
|
assert resp.status_code == 200
|
|
resp = client.get("/api/auth/me", headers={"Authorization": f"Bearer {token}"})
|
|
assert resp.status_code == 401
|
|
|
|
|
|
# ── Health check ──
|
|
|
|
def test_health():
|
|
resp = client.get("/api/health")
|
|
assert resp.status_code == 200
|
|
assert resp.json()["status"] == "ok"
|