rebase
This commit is contained in:
89
tests/unit/test_security.py
Normal file
89
tests/unit/test_security.py
Normal file
@@ -0,0 +1,89 @@
|
||||
"""Tests for `app.core.security` — JWT and password hashing."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
from jose import JWTError
|
||||
|
||||
from app.core.security import (
|
||||
create_access_token,
|
||||
create_refresh_token,
|
||||
decode_token,
|
||||
hash_password,
|
||||
validate_password_strength,
|
||||
verify_password,
|
||||
)
|
||||
|
||||
|
||||
def test_password_hash_and_verify():
|
||||
plain = "S3cretPass!"
|
||||
hashed = hash_password(plain)
|
||||
assert hashed != plain
|
||||
assert verify_password(plain, hashed) is True
|
||||
assert verify_password("wrong", hashed) is False
|
||||
|
||||
|
||||
def test_password_hash_is_bcrypt():
|
||||
hashed = hash_password("S3cretPass!")
|
||||
# bcrypt hashes start with $2b$ or $2a$
|
||||
assert hashed.startswith("$2")
|
||||
|
||||
|
||||
def test_validate_password_strength_strong():
|
||||
errors = validate_password_strength("GoodPass123")
|
||||
assert errors == []
|
||||
|
||||
|
||||
def test_validate_password_strength_short():
|
||||
errors = validate_password_strength("abc12")
|
||||
assert any("8 characters" in e for e in errors)
|
||||
|
||||
|
||||
def test_validate_password_strength_no_digit():
|
||||
errors = validate_password_strength("NoDigitsHere")
|
||||
assert any("digit" in e for e in errors)
|
||||
|
||||
|
||||
def test_validate_password_strength_no_letter():
|
||||
errors = validate_password_strength("12345678")
|
||||
assert any("letter" in e for e in errors)
|
||||
|
||||
|
||||
def test_validate_password_strength_blacklist():
|
||||
errors = validate_password_strength("password1")
|
||||
assert any("common" in e for e in errors)
|
||||
|
||||
|
||||
def test_create_and_decode_access_token():
|
||||
uid = uuid.uuid4()
|
||||
token = create_access_token(uid, extra_claims={"is_admin": True})
|
||||
payload = decode_token(token)
|
||||
assert payload["sub"] == str(uid)
|
||||
assert payload["type"] == "access"
|
||||
assert payload["is_admin"] is True
|
||||
assert "iat" in payload and "exp" in payload
|
||||
|
||||
|
||||
def test_create_and_decode_refresh_token():
|
||||
uid = uuid.uuid4()
|
||||
token = create_refresh_token(uid)
|
||||
payload = decode_token(token)
|
||||
assert payload["sub"] == str(uid)
|
||||
assert payload["type"] == "refresh"
|
||||
|
||||
|
||||
def test_decode_invalid_token():
|
||||
with pytest.raises(JWTError):
|
||||
decode_token("not-a-valid-jwt")
|
||||
|
||||
|
||||
def test_token_expiry_in_future():
|
||||
uid = uuid.uuid4()
|
||||
token = create_access_token(uid, expires_in_minutes=60)
|
||||
payload = decode_token(token)
|
||||
now = int(time.time())
|
||||
assert payload["exp"] > now
|
||||
assert payload["iat"] <= now
|
||||
Reference in New Issue
Block a user