86 lines
2.8 KiB
Python
86 lines
2.8 KiB
Python
import pytest
|
|
from datetime import datetime, timezone, timedelta
|
|
|
|
from app.services.auth import (
|
|
get_password_hash,
|
|
verify_password,
|
|
create_access_token,
|
|
decode_token,
|
|
)
|
|
|
|
|
|
class TestPasswordHashing:
|
|
"""Tests for password hashing functions."""
|
|
|
|
def test_hash_password(self):
|
|
"""Test that password hashing works."""
|
|
password = "securepassword123"
|
|
hashed = get_password_hash(password)
|
|
assert hashed != password
|
|
assert len(hashed) > 0
|
|
|
|
def test_verify_correct_password(self):
|
|
"""Test verifying correct password."""
|
|
password = "securepassword123"
|
|
hashed = get_password_hash(password)
|
|
assert verify_password(password, hashed) is True
|
|
|
|
def test_verify_wrong_password(self):
|
|
"""Test verifying wrong password."""
|
|
password = "securepassword123"
|
|
hashed = get_password_hash(password)
|
|
assert verify_password("wrongpassword", hashed) is False
|
|
|
|
def test_hash_is_unique(self):
|
|
"""Test that same password produces different hashes (salt)."""
|
|
password = "securepassword123"
|
|
hash1 = get_password_hash(password)
|
|
hash2 = get_password_hash(password)
|
|
assert hash1 != hash2 # Different salts
|
|
|
|
def test_long_password_truncated(self):
|
|
"""Test that long passwords work (bcrypt 72 byte limit)."""
|
|
long_password = "a" * 100
|
|
hashed = get_password_hash(long_password)
|
|
assert verify_password(long_password, hashed) is True
|
|
|
|
|
|
class TestJWT:
|
|
"""Tests for JWT token functions."""
|
|
|
|
def test_create_token(self):
|
|
"""Test creating a JWT token."""
|
|
token = create_access_token(data={"sub": "123"})
|
|
assert token is not None
|
|
assert len(token) > 0
|
|
|
|
def test_decode_valid_token(self):
|
|
"""Test decoding a valid token."""
|
|
user_id = "123"
|
|
token = create_access_token(data={"sub": user_id})
|
|
payload = decode_token(token)
|
|
assert payload is not None
|
|
assert payload["sub"] == user_id
|
|
|
|
def test_decode_invalid_token(self):
|
|
"""Test decoding an invalid token."""
|
|
payload = decode_token("invalid.token.here")
|
|
assert payload is None
|
|
|
|
def test_decode_expired_token(self):
|
|
"""Test that expired tokens are rejected."""
|
|
# Create a token that expires immediately
|
|
token = create_access_token(
|
|
data={"sub": "123"},
|
|
expires_delta=timedelta(seconds=-1), # Already expired
|
|
)
|
|
payload = decode_token(token)
|
|
assert payload is None
|
|
|
|
def test_token_contains_expiry(self):
|
|
"""Test that token contains expiration claim."""
|
|
token = create_access_token(data={"sub": "123"})
|
|
payload = decode_token(token)
|
|
assert payload is not None
|
|
assert "exp" in payload
|