feat: Add unique constraint on sound hash and update related tests
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
import json
|
||||
from collections.abc import AsyncGenerator
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
@@ -19,7 +20,7 @@ class TestCreditTransactionRepository:
|
||||
async def credit_transaction_repository(
|
||||
self,
|
||||
test_session: AsyncSession,
|
||||
) -> AsyncGenerator[CreditTransactionRepository, None]: # type: ignore[misc]
|
||||
) -> AsyncGenerator[CreditTransactionRepository, None]:
|
||||
"""Create a credit transaction repository instance."""
|
||||
yield CreditTransactionRepository(test_session)
|
||||
|
||||
@@ -29,6 +30,7 @@ class TestCreditTransactionRepository:
|
||||
test_user: User,
|
||||
) -> int:
|
||||
"""Get test user ID to avoid lazy loading issues."""
|
||||
assert test_user.id is not None
|
||||
return test_user.id
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
@@ -36,7 +38,7 @@ class TestCreditTransactionRepository:
|
||||
self,
|
||||
test_session: AsyncSession,
|
||||
test_user_id: int,
|
||||
) -> AsyncGenerator[list[CreditTransaction], None]: # type: ignore[misc]
|
||||
) -> AsyncGenerator[list[CreditTransaction], None]:
|
||||
"""Create test credit transactions."""
|
||||
transactions = []
|
||||
user_id = test_user_id
|
||||
@@ -100,8 +102,8 @@ class TestCreditTransactionRepository:
|
||||
async def other_user_transaction(
|
||||
self,
|
||||
test_session: AsyncSession,
|
||||
ensure_plans: tuple, # noqa: ARG002
|
||||
) -> AsyncGenerator[CreditTransaction, None]: # type: ignore[misc]
|
||||
ensure_plans: tuple[Any, ...], # noqa: ARG002
|
||||
) -> AsyncGenerator[CreditTransaction, None]:
|
||||
"""Create a transaction for a different user."""
|
||||
from app.models.plan import Plan
|
||||
from app.repositories.user import UserRepository
|
||||
@@ -142,7 +144,9 @@ class TestCreditTransactionRepository:
|
||||
test_transactions: list[CreditTransaction],
|
||||
) -> None:
|
||||
"""Test getting transaction by ID when it exists."""
|
||||
transaction = await credit_transaction_repository.get_by_id(test_transactions[0].id)
|
||||
transaction_id = test_transactions[0].id
|
||||
assert transaction_id is not None
|
||||
transaction = await credit_transaction_repository.get_by_id(transaction_id)
|
||||
|
||||
assert transaction is not None
|
||||
assert transaction.id == test_transactions[0].id
|
||||
@@ -342,6 +346,7 @@ class TestCreditTransactionRepository:
|
||||
assert transaction.balance_before == 100
|
||||
assert transaction.balance_after == 90
|
||||
assert transaction.success is True
|
||||
assert transaction.metadata_json is not None
|
||||
assert json.loads(transaction.metadata_json) == {"test": "data"}
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -363,6 +368,7 @@ class TestCreditTransactionRepository:
|
||||
|
||||
assert updated_transaction.id == transaction.id
|
||||
assert updated_transaction.description == "Updated description"
|
||||
assert updated_transaction.metadata_json is not None
|
||||
assert json.loads(updated_transaction.metadata_json) == {"updated": True}
|
||||
# Other fields should remain unchanged
|
||||
assert updated_transaction.amount == transaction.amount
|
||||
@@ -394,6 +400,7 @@ class TestCreditTransactionRepository:
|
||||
await credit_transaction_repository.delete(transaction)
|
||||
|
||||
# Verify transaction is deleted
|
||||
assert transaction_id is not None
|
||||
deleted_transaction = await credit_transaction_repository.get_by_id(transaction_id)
|
||||
assert deleted_transaction is None
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class TestSoundRepository:
|
||||
async def sound_repository(
|
||||
self,
|
||||
test_session: AsyncSession,
|
||||
) -> AsyncGenerator[SoundRepository, None]: # type: ignore[misc]
|
||||
) -> AsyncGenerator[SoundRepository, None]:
|
||||
"""Create a sound repository instance."""
|
||||
yield SoundRepository(test_session)
|
||||
|
||||
@@ -25,7 +25,7 @@ class TestSoundRepository:
|
||||
async def test_sound(
|
||||
self,
|
||||
test_session: AsyncSession,
|
||||
) -> AsyncGenerator[Sound, None]: # type: ignore[misc]
|
||||
) -> AsyncGenerator[Sound, None]:
|
||||
"""Create a test sound."""
|
||||
sound_data = {
|
||||
"name": "Test Sound",
|
||||
@@ -47,7 +47,7 @@ class TestSoundRepository:
|
||||
async def normalized_sound(
|
||||
self,
|
||||
test_session: AsyncSession,
|
||||
) -> AsyncGenerator[Sound, None]: # type: ignore[misc]
|
||||
) -> AsyncGenerator[Sound, None]:
|
||||
"""Create a normalized test sound."""
|
||||
sound_data = {
|
||||
"name": "Normalized Sound",
|
||||
@@ -76,7 +76,9 @@ class TestSoundRepository:
|
||||
test_sound: Sound,
|
||||
) -> None:
|
||||
"""Test getting sound by ID when it exists."""
|
||||
sound = await sound_repository.get_by_id(test_sound.id)
|
||||
sound_id = test_sound.id
|
||||
assert sound_id is not None
|
||||
sound = await sound_repository.get_by_id(sound_id)
|
||||
|
||||
assert sound is not None
|
||||
assert sound.id == test_sound.id
|
||||
@@ -240,6 +242,7 @@ class TestSoundRepository:
|
||||
await sound_repository.delete(sound)
|
||||
|
||||
# Verify sound is deleted
|
||||
assert sound_id is not None
|
||||
deleted_sound = await sound_repository.get_by_id(sound_id)
|
||||
assert deleted_sound is None
|
||||
|
||||
@@ -353,7 +356,7 @@ class TestSoundRepository:
|
||||
sound_repository: SoundRepository,
|
||||
test_sound: Sound,
|
||||
) -> None:
|
||||
"""Test creating sound with duplicate hash is allowed."""
|
||||
"""Test creating sound with duplicate hash should fail."""
|
||||
# Store the hash to avoid lazy loading issues
|
||||
original_hash = test_sound.hash
|
||||
|
||||
@@ -368,9 +371,6 @@ class TestSoundRepository:
|
||||
"is_normalized": False,
|
||||
}
|
||||
|
||||
# Should succeed - duplicate hashes are allowed
|
||||
duplicate_sound = await sound_repository.create(duplicate_sound_data)
|
||||
|
||||
assert duplicate_sound.id is not None
|
||||
assert duplicate_sound.name == "Duplicate Hash Sound"
|
||||
assert duplicate_sound.hash == original_hash # Same hash is allowed
|
||||
# Should fail due to unique constraint on hash
|
||||
with pytest.raises(Exception): # SQLAlchemy IntegrityError or similar
|
||||
await sound_repository.create(duplicate_sound_data)
|
||||
@@ -18,7 +18,7 @@ class TestUserOauthRepository:
|
||||
async def user_oauth_repository(
|
||||
self,
|
||||
test_session: AsyncSession,
|
||||
) -> AsyncGenerator[UserOauthRepository, None]: # type: ignore[misc]
|
||||
) -> AsyncGenerator[UserOauthRepository, None]:
|
||||
"""Create a user OAuth repository instance."""
|
||||
yield UserOauthRepository(test_session)
|
||||
|
||||
@@ -28,6 +28,7 @@ class TestUserOauthRepository:
|
||||
test_user: User,
|
||||
) -> int:
|
||||
"""Get test user ID to avoid lazy loading issues."""
|
||||
assert test_user.id is not None
|
||||
return test_user.id
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
@@ -35,7 +36,7 @@ class TestUserOauthRepository:
|
||||
self,
|
||||
test_session: AsyncSession,
|
||||
test_user_id: int,
|
||||
) -> AsyncGenerator[UserOauth, None]: # type: ignore[misc]
|
||||
) -> AsyncGenerator[UserOauth, None]:
|
||||
"""Create a test OAuth record."""
|
||||
oauth_data = {
|
||||
"user_id": test_user_id,
|
||||
|
||||
Reference in New Issue
Block a user