Spaces:
Runtime error
Runtime error
File size: 6,906 Bytes
02427e3 148b563 02427e3 148b563 02427e3 148b563 02427e3 148b563 02427e3 148b563 02427e3 148b563 02427e3 148b563 02427e3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | from datetime import datetime, timedelta, timezone
import jwt
from app.config import settings
def test_signup_valid(client):
response = client.post("/api/v1/auth/signup", json={"email": "test@example.com", "password": "ValidPass123"})
assert response.status_code == 201
data = response.json()
assert data["email"] == "test@example.com"
assert data["role"] == "owner"
assert "password_hash" not in data
def test_signup_duplicate_email_case_insensitive(client):
client.post("/api/v1/auth/signup", json={"email": "Test@Example.com", "password": "ValidPass123"})
response = client.post("/api/v1/auth/signup", json={"email": "test@example.com", "password": "ValidPass123"})
assert response.status_code == 409
assert response.json()["error"]["code"] == "EMAIL_ALREADY_REGISTERED"
def test_signup_weak_password(client):
response = client.post("/api/v1/auth/signup", json={"email": "weak@example.com", "password": "abc"})
assert response.status_code == 422
fields = [d["field"] for d in response.json()["error"]["details"]]
assert "body.password" in fields
def test_signup_password_over_72_bytes(client):
response = client.post("/api/v1/auth/signup", json={"email": "emoji@example.com", "password": "😀" * 40})
assert response.status_code == 422
fields = [d["field"] for d in response.json()["error"]["details"]]
assert "body.password" in fields
def test_signup_extra_field_forbidden(client):
response = client.post("/api/v1/auth/signup", json={"email": "hacker@example.com", "password": "ValidPass123", "role": "admin"})
assert response.status_code == 422
fields = [d["field"] for d in response.json()["error"]["details"]]
assert "body.role" in fields
def test_login_valid(client):
client.post("/api/v1/auth/signup", json={"email": "login@example.com", "password": "ValidPass123"})
response = client.post("/api/v1/auth/login", json={"email": "login@example.com", "password": "ValidPass123"})
assert response.status_code == 200
assert "access_token" in response.json()
def test_login_wrong_password_and_unknown_email_look_identical(client):
client.post("/api/v1/auth/signup", json={"email": "real@example.com", "password": "ValidPass123"})
r1 = client.post("/api/v1/auth/login", json={"email": "real@example.com", "password": "WrongPass123"})
r2 = client.post("/api/v1/auth/login", json={"email": "unknown@example.com", "password": "ValidPass123"})
assert r1.status_code == 401
assert r2.status_code == 401
# Compare the error fields, ignoring the request_id (which is unique per request)
err1 = r1.json()["error"]
err2 = r2.json()["error"]
assert err1["code"] == err2["code"]
assert err1["message"] == err2["message"]
assert err1["status"] == err2["status"]
assert err1["details"] == err2["details"]
def test_protected_route_no_header(client):
response = client.get("/api/v1/protected")
assert response.status_code == 401
assert response.json()["error"]["code"] == "AUTH_MISSING"
def test_protected_route_garbage_token(client):
response = client.get("/api/v1/protected", headers={"Authorization": "Bearer not.a.jwt"})
assert response.status_code == 401
assert response.json()["error"]["code"] == "TOKEN_INVALID"
def test_protected_route_expired_token(client):
client.post("/api/v1/auth/signup", json={"email": "expired@example.com", "password": "ValidPass123"})
login = client.post("/api/v1/auth/login", json={"email": "expired@example.com", "password": "ValidPass123"})
user_id = jwt.decode(login.json()["access_token"], options={"verify_signature": False})["sub"]
now = datetime.now(timezone.utc)
expired_token = jwt.encode(
{"sub": user_id, "role": "owner", "iat": now - timedelta(hours=2), "exp": now - timedelta(hours=1)},
settings.JWT_SECRET_KEY, algorithm="HS256"
)
response = client.get("/api/v1/protected", headers={"Authorization": f"Bearer {expired_token}"})
assert response.status_code == 401
assert response.json()["error"]["code"] == "TOKEN_EXPIRED"
def test_protected_route_valid_token(client):
client.post("/api/v1/auth/signup", json={"email": "valid@example.com", "password": "ValidPass123"})
login = client.post("/api/v1/auth/login", json={"email": "valid@example.com", "password": "ValidPass123"})
response = client.get("/api/v1/protected", headers={"Authorization": f"Bearer {login.json()['access_token']}"})
assert response.status_code == 200
def test_change_password_success_and_login(client):
client.post("/api/v1/auth/signup", json={"email": "change@example.com", "password": "OldPass123"})
login = client.post("/api/v1/auth/login", json={"email": "change@example.com", "password": "OldPass123"})
token = login.json()["access_token"]
response = client.put(
"/api/v1/auth/change-password",
headers={"Authorization": f"Bearer {token}"},
json={"current_password": "OldPass123", "new_password": "NewPass456"}
)
assert response.status_code == 200
old_login = client.post("/api/v1/auth/login", json={"email": "change@example.com", "password": "OldPass123"})
assert old_login.status_code == 401
new_login = client.post("/api/v1/auth/login", json={"email": "change@example.com", "password": "NewPass456"})
assert new_login.status_code == 200
def test_change_password_wrong_current_password(client):
client.post("/api/v1/auth/signup", json={"email": "wrongcur@example.com", "password": "OldPass123"})
login = client.post("/api/v1/auth/login", json={"email": "wrongcur@example.com", "password": "OldPass123"})
response = client.put(
"/api/v1/auth/change-password",
headers={"Authorization": f"Bearer {login.json()['access_token']}"},
json={"current_password": "WrongOldPass", "new_password": "NewPass456"}
)
assert response.status_code == 401
assert response.json()["error"]["code"] == "INVALID_CREDENTIALS"
def test_change_password_requires_auth(client):
response = client.put("/api/v1/auth/change-password", json={"current_password": "OldPass123", "new_password": "NewPass456"})
assert response.status_code == 401
assert response.json()["error"]["code"] == "AUTH_MISSING"
def test_change_password_weak_new_password(client):
client.post("/api/v1/auth/signup", json={"email": "weaknew@example.com", "password": "OldPass123"})
login = client.post("/api/v1/auth/login", json={"email": "weaknew@example.com", "password": "OldPass123"})
response = client.put(
"/api/v1/auth/change-password",
headers={"Authorization": f"Bearer {login.json()['access_token']}"},
json={"current_password": "OldPass123", "new_password": "abc"}
)
assert response.status_code == 422
assert "body.new_password" in [d["field"] for d in response.json()["error"]["details"]] |