Spaces:
Sleeping
Sleeping
| """ | |
| Unit tests for authentication functionality | |
| """ | |
| import pytest | |
| import asyncio | |
| from unittest.mock import AsyncMock, MagicMock, patch | |
| from fastapi.testclient import TestClient | |
| from fastapi import HTTPException | |
| from passlib.context import CryptContext | |
| import jwt | |
| from datetime import datetime, timedelta | |
| from ..auth.auth import AuthHandler, get_password_hash, verify_password, create_access_token, decode_access_token | |
| from ..auth.schemas import UserCreate, UserLogin, TokenData | |
| from ..config.settings import settings | |
| pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") | |
| def auth_handler(): | |
| """Fixture to create an instance of AuthHandler for testing""" | |
| return AuthHandler() | |
| async def test_verify_password(): | |
| """Test password verification""" | |
| plain_password = "test_password" | |
| hashed_password = get_password_hash(plain_password) | |
| # Test correct password | |
| assert verify_password(plain_password, hashed_password) == True | |
| # Test incorrect password | |
| assert verify_password("wrong_password", hashed_password) == False | |
| def test_get_password_hash(): | |
| """Test password hashing""" | |
| password = "test_password" | |
| hashed = get_password_hash(password) | |
| # Verify it's properly hashed | |
| assert hashed != password | |
| assert len(hashed) > 0 | |
| assert "$2b$" in hashed # bcrypt hash identifier | |
| async def test_create_access_token(): | |
| """Test creating access token""" | |
| data = {"sub": "test_user", "user_id": "test_id"} | |
| token = create_access_token(data) | |
| # Verify token is created | |
| assert token is not None | |
| assert isinstance(token, str) | |
| assert len(token) > 0 | |
| # Decode and verify contents | |
| decoded = jwt.decode(token, settings.secret_key, algorithms=[settings.jwt_algorithm]) | |
| assert decoded["sub"] == "test_user" | |
| assert decoded["user_id"] == "test_id" | |
| async def test_decode_access_token(): | |
| """Test decoding access token""" | |
| data = {"sub": "test_user", "user_id": "test_id"} | |
| token = create_access_token(data) | |
| # Test valid token | |
| decoded = decode_access_token(token) | |
| assert decoded is not None | |
| assert decoded.username == "test_user" | |
| assert decoded.user_id == "test_id" | |
| # Test invalid token | |
| invalid_token = "invalid.token.string" | |
| decoded_invalid = decode_access_token(invalid_token) | |
| assert decoded_invalid is None | |
| async def test_decode_expired_token(): | |
| """Test decoding an expired token""" | |
| with patch('datetime.datetime') as mock_datetime: | |
| mock_datetime.utcnow.return_value = datetime.utcnow() - timedelta(days=1) | |
| data = {"sub": "test_user", "user_id": "test_id"} | |
| # Create a token that expires immediately | |
| token = create_access_token(data, expires_delta=timedelta(seconds=-1)) | |
| decoded = decode_access_token(token) | |
| assert decoded is None | |
| async def test_auth_handler_creation(): | |
| """Test AuthHandler initialization""" | |
| auth = AuthHandler() | |
| assert auth.secret_key == settings.secret_key | |
| assert auth.algorithm == settings.jwt_algorithm | |
| assert auth.access_token_expires == timedelta(seconds=settings.jwt_expires_in) | |
| async def test_get_current_user_dependency(): | |
| """Test the get_current_user dependency function""" | |
| data = {"sub": "test_user", "user_id": "test_id"} | |
| token = create_access_token(data) | |
| # Mock the security dependency | |
| with patch('fastapi.security.http.HTTPAuthorizationCredentials') as mock_cred: | |
| mock_cred.credentials = token | |
| # Test the dependency function (this would normally be used in FastAPI routes) | |
| # Since we can't easily test the actual dependency injection, we'll test the underlying functionality | |
| decoded = decode_access_token(token) | |
| assert decoded is not None | |
| assert decoded.username == "test_user" | |
| async def test_password_hash_consistency(): | |
| """Test that password hashing is consistent""" | |
| password = "consistent_test_password" | |
| # Hash the same password multiple times | |
| hash1 = get_password_hash(password) | |
| hash2 = get_password_hash(password) | |
| # Different hashes each time (due to salt) but both should verify the same password | |
| assert hash1 != hash2 | |
| assert verify_password(password, hash1) == True | |
| assert verify_password(password, hash2) == True |