""" 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