chartbastan/backend/tests/test_api_key_service.py
2026-02-01 09:31:38 +01:00

204 lines
6.7 KiB
Python

"""
Tests for API Key Service.
This module tests the API key generation, validation, and management.
"""
import pytest
from sqlalchemy.orm import Session
from app.services.apiKeyService import ApiKeyService
from app.models.api_key import ApiKey
from app.models.user import User
@pytest.fixture
def sample_user(db: Session):
"""Create a sample user for testing."""
user = User(
email="test@example.com",
name="Test User",
is_premium=False
)
db.add(user)
db.commit()
db.refresh(user)
return user
class TestApiKeyGeneration:
"""Tests for API key generation."""
def test_generate_api_key_success(self, db: Session, sample_user: User):
"""Test successful API key generation."""
service = ApiKeyService(db)
result = service.generate_api_key(sample_user.id, rate_limit=100)
assert "api_key" in result
assert "id" in result
assert "key_prefix" in result
assert "user_id" in result
assert result["user_id"] == sample_user.id
assert result["rate_limit"] == 100
assert result["is_active"] == True
assert len(result["api_key"]) > 0
assert len(result["key_prefix"]) == 8
def test_generate_api_key_invalid_user(self, db: Session):
"""Test API key generation with invalid user ID."""
service = ApiKeyService(db)
with pytest.raises(ValueError) as exc_info:
service.generate_api_key(99999)
assert "not found" in str(exc_info.value).lower()
def test_generate_api_key_stores_hash(self, db: Session, sample_user: User):
"""Test that API key stores hash instead of plain key."""
service = ApiKeyService(db)
result = service.generate_api_key(sample_user.id)
# Query the database to verify hash is stored
api_key_record = db.query(ApiKey).filter(
ApiKey.id == result["id"]
).first()
assert api_key_record is not None
assert api_key_record.key_hash != result["api_key"]
assert len(api_key_record.key_hash) == 64 # SHA-256 hash length
assert api_key_record.key_prefix == result["api_key"][:8]
class TestApiKeyValidation:
"""Tests for API key validation."""
def test_validate_api_key_success(self, db: Session, sample_user: User):
"""Test successful API key validation."""
service = ApiKeyService(db)
result = service.generate_api_key(sample_user.id)
plain_api_key = result["api_key"]
# Validate the key
validated = service.validate_api_key(plain_api_key)
assert validated is not None
assert validated.user_id == sample_user.id
assert validated.is_active == True
def test_validate_api_key_invalid(self, db: Session):
"""Test validation with invalid API key."""
service = ApiKeyService(db)
validated = service.validate_api_key("invalid_key_12345")
assert validated is None
def test_validate_api_key_updates_last_used(self, db: Session, sample_user: User):
"""Test that validation updates last_used_at timestamp."""
service = ApiKeyService(db)
result = service.generate_api_key(sample_user.id)
plain_api_key = result["api_key"]
# Validate the key
validated = service.validate_api_key(plain_api_key)
assert validated.last_used_at is not None
def test_validate_api_key_inactive(self, db: Session, sample_user: User):
"""Test validation with inactive API key."""
service = ApiKeyService(db)
result = service.generate_api_key(sample_user.id)
plain_api_key = result["api_key"]
# Deactivate the key
api_key_record = db.query(ApiKey).filter(
ApiKey.id == result["id"]
).first()
api_key_record.is_active = False
db.commit()
# Try to validate
validated = service.validate_api_key(plain_api_key)
assert validated is None
class TestApiKeyManagement:
"""Tests for API key management."""
def test_get_user_api_keys(self, db: Session, sample_user: User):
"""Test retrieving all API keys for a user."""
service = ApiKeyService(db)
# Generate 3 keys
keys = []
for i in range(3):
result = service.generate_api_key(sample_user.id)
keys.append(result)
# Retrieve all keys
user_keys = service.get_user_api_keys(sample_user.id)
assert len(user_keys) == 3
# Verify plain keys are not included
for key in user_keys:
assert "api_key" not in key
assert "key_prefix" in key
def test_revoke_api_key_success(self, db: Session, sample_user: User):
"""Test successful API key revocation."""
service = ApiKeyService(db)
result = service.generate_api_key(sample_user.id)
api_key_id = result["id"]
# Revoke the key
revoked = service.revoke_api_key(api_key_id, sample_user.id)
assert revoked is True
# Verify it's deactivated
api_key_record = db.query(ApiKey).filter(
ApiKey.id == api_key_id
).first()
assert api_key_record.is_active == False
def test_revoke_api_key_wrong_user(self, db: Session, sample_user: User):
"""Test revoking key with wrong user ID."""
service = ApiKeyService(db)
result = service.generate_api_key(sample_user.id)
api_key_id = result["id"]
# Try to revoke with wrong user ID
revoked = service.revoke_api_key(api_key_id, 99999)
assert revoked is False
def test_regenerate_api_key_success(self, db: Session, sample_user: User):
"""Test successful API key regeneration."""
service = ApiKeyService(db)
old_result = service.generate_api_key(sample_user.id)
old_api_key_id = old_result["id"]
# Regenerate
new_result = service.regenerate_api_key(old_api_key_id, sample_user.id)
assert new_result is not None
assert "api_key" in new_result
assert new_result["api_key"] != old_result["api_key"]
assert new_result["id"] != old_api_key_id
# Verify old key is deactivated
old_key_record = db.query(ApiKey).filter(
ApiKey.id == old_api_key_id
).first()
assert old_key_record.is_active == False
def test_regenerate_api_key_wrong_user(self, db: Session, sample_user: User):
"""Test regenerating key with wrong user ID."""
service = ApiKeyService(db)
old_result = service.generate_api_key(sample_user.id)
# Try to regenerate with wrong user ID
new_result = service.regenerate_api_key(old_result["id"], 99999)
assert new_result is None