204 lines
6.7 KiB
Python
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
|