Refactor test cases for improved readability and consistency
All checks were successful
Backend CI / lint (push) Successful in 9m49s
Backend CI / test (push) Successful in 6m15s

- Adjusted function signatures in various test files to enhance clarity by aligning parameters.
- Updated patching syntax for better readability across test cases.
- Improved formatting and spacing in test assertions and mock setups.
- Ensured consistent use of async/await patterns in async test functions.
- Enhanced comments for better understanding of test intentions.
This commit is contained in:
JSC
2025-08-01 20:53:30 +02:00
parent d926779fe4
commit 6068599a47
39 changed files with 691 additions and 286 deletions

View File

@@ -1 +1 @@
"""Tests for admin API endpoints."""
"""Tests for admin API endpoints."""

View File

@@ -73,7 +73,9 @@ class TestAdminSoundEndpoints:
) as mock_scan:
mock_scan.return_value = mock_results
response = await authenticated_admin_client.post("/api/v1/admin/sounds/scan")
response = await authenticated_admin_client.post(
"/api/v1/admin/sounds/scan",
)
assert response.status_code == 200
data = response.json()
@@ -114,6 +116,7 @@ class TestAdminSoundEndpoints:
) -> None:
"""Test scanning sounds with non-admin user."""
from fastapi import HTTPException
from app.core.dependencies import get_admin_user
# Override the admin dependency to raise 403 for non-admin users
@@ -150,7 +153,9 @@ class TestAdminSoundEndpoints:
) as mock_scan:
mock_scan.side_effect = Exception("Directory not found")
response = await authenticated_admin_client.post("/api/v1/admin/sounds/scan")
response = await authenticated_admin_client.post(
"/api/v1/admin/sounds/scan",
)
assert response.status_code == 500
data = response.json()
@@ -300,7 +305,9 @@ class TestAdminSoundEndpoints:
assert len(results["files"]) == 3
@pytest.mark.asyncio
async def test_normalize_all_sounds_unauthenticated(self, client: AsyncClient) -> None:
async def test_normalize_all_sounds_unauthenticated(
self, client: AsyncClient,
) -> None:
"""Test normalizing sounds without authentication."""
response = await client.post("/api/v1/admin/sounds/normalize/all")
@@ -316,6 +323,7 @@ class TestAdminSoundEndpoints:
) -> None:
"""Test normalizing sounds with non-admin user."""
from fastapi import HTTPException
from app.core.dependencies import get_admin_user
# Override the admin dependency to raise 403 for non-admin users
@@ -331,7 +339,8 @@ class TestAdminSoundEndpoints:
base_url="http://test",
) as client:
response = await client.post(
"/api/v1/admin/sounds/normalize/all", headers=headers,
"/api/v1/admin/sounds/normalize/all",
headers=headers,
)
assert response.status_code == 403
@@ -405,7 +414,9 @@ class TestAdminSoundEndpoints:
# Verify the service was called with correct type
mock_normalize.assert_called_once_with(
sound_type="SDB", force=False, one_pass=None,
sound_type="SDB",
force=False,
one_pass=None,
)
@pytest.mark.asyncio
@@ -491,7 +502,7 @@ class TestAdminSoundEndpoints:
) -> None:
"""Test getting extraction processor status."""
with patch(
"app.services.extraction_processor.extraction_processor.get_status"
"app.services.extraction_processor.extraction_processor.get_status",
) as mock_get_status:
mock_status = {
"is_running": True,
@@ -502,7 +513,7 @@ class TestAdminSoundEndpoints:
mock_get_status.return_value = mock_status
response = await authenticated_admin_client.get(
"/api/v1/admin/sounds/extract/status"
"/api/v1/admin/sounds/extract/status",
)
assert response.status_code == 200
@@ -511,7 +522,8 @@ class TestAdminSoundEndpoints:
@pytest.mark.asyncio
async def test_get_extraction_processor_status_unauthenticated(
self, client: AsyncClient
self,
client: AsyncClient,
) -> None:
"""Test getting extraction processor status without authentication."""
response = await client.get("/api/v1/admin/sounds/extract/status")
@@ -528,6 +540,7 @@ class TestAdminSoundEndpoints:
) -> None:
"""Test getting extraction processor status with non-admin user."""
from fastapi import HTTPException
from app.core.dependencies import get_admin_user
# Override the admin dependency to raise 403 for non-admin users
@@ -543,7 +556,8 @@ class TestAdminSoundEndpoints:
base_url="http://test",
) as client:
response = await client.get(
"/api/v1/admin/sounds/extract/status", headers=headers
"/api/v1/admin/sounds/extract/status",
headers=headers,
)
assert response.status_code == 403
@@ -551,4 +565,4 @@ class TestAdminSoundEndpoints:
assert "Not enough permissions" in data["detail"]
# Clean up override
test_app.dependency_overrides.pop(get_admin_user, None)
test_app.dependency_overrides.pop(get_admin_user, None)

View File

@@ -54,7 +54,11 @@ class TestApiTokenEndpoints:
expires_at_str = data["expires_at"]
# Handle both ISO format with/without timezone info
if expires_at_str.endswith("Z") or "+" in expires_at_str or expires_at_str.count("-") > 2:
if (
expires_at_str.endswith("Z")
or "+" in expires_at_str
or expires_at_str.count("-") > 2
):
expires_at = datetime.fromisoformat(expires_at_str)
else:
# Naive datetime, assume UTC
@@ -84,7 +88,11 @@ class TestApiTokenEndpoints:
expires_at_str = data["expires_at"]
# Handle both ISO format with/without timezone info
if expires_at_str.endswith("Z") or "+" in expires_at_str or expires_at_str.count("-") > 2:
if (
expires_at_str.endswith("Z")
or "+" in expires_at_str
or expires_at_str.count("-") > 2
):
expires_at = datetime.fromisoformat(expires_at_str)
else:
# Naive datetime, assume UTC
@@ -116,7 +124,9 @@ class TestApiTokenEndpoints:
assert response.status_code == 422
@pytest.mark.asyncio
async def test_generate_api_token_unauthenticated(self, client: AsyncClient) -> None:
async def test_generate_api_token_unauthenticated(
self, client: AsyncClient,
) -> None:
"""Test API token generation without authentication."""
response = await client.post(
"/api/v1/auth/api-token",
@@ -186,7 +196,9 @@ class TestApiTokenEndpoints:
assert data["is_expired"] is True
@pytest.mark.asyncio
async def test_get_api_token_status_unauthenticated(self, client: AsyncClient) -> None:
async def test_get_api_token_status_unauthenticated(
self, client: AsyncClient,
) -> None:
"""Test getting API token status without authentication."""
response = await client.get("/api/v1/auth/api-token/status")
assert response.status_code == 401
@@ -264,7 +276,9 @@ class TestApiTokenEndpoints:
assert "email" in data
@pytest.mark.asyncio
async def test_api_token_authentication_invalid_token(self, client: AsyncClient) -> None:
async def test_api_token_authentication_invalid_token(
self, client: AsyncClient,
) -> None:
"""Test authentication with invalid API token."""
headers = {"API-TOKEN": "invalid_token"}
response = await client.get("/api/v1/auth/me", headers=headers)
@@ -297,7 +311,9 @@ class TestApiTokenEndpoints:
assert "API token has expired" in data["detail"]
@pytest.mark.asyncio
async def test_api_token_authentication_empty_token(self, client: AsyncClient) -> None:
async def test_api_token_authentication_empty_token(
self, client: AsyncClient,
) -> None:
"""Test authentication with empty API-TOKEN header."""
# Empty token
headers = {"API-TOKEN": ""}

View File

@@ -1,6 +1,5 @@
"""Tests for extraction API endpoints."""
import pytest
from httpx import AsyncClient
@@ -10,7 +9,9 @@ class TestExtractionEndpoints:
@pytest.mark.asyncio
async def test_create_extraction_success(
self, test_client: AsyncClient, auth_cookies: dict[str, str],
self,
test_client: AsyncClient,
auth_cookies: dict[str, str],
) -> None:
"""Test successful extraction creation."""
# Set cookies on client instance to avoid deprecation warning
@@ -26,7 +27,9 @@ class TestExtractionEndpoints:
assert response.status_code in [200, 400, 500] # Allow any non-auth error
@pytest.mark.asyncio
async def test_create_extraction_unauthenticated(self, test_client: AsyncClient) -> None:
async def test_create_extraction_unauthenticated(
self, test_client: AsyncClient,
) -> None:
"""Test extraction creation without authentication."""
response = await test_client.post(
"/api/v1/sounds/extract",
@@ -37,7 +40,9 @@ class TestExtractionEndpoints:
assert response.status_code == 401
@pytest.mark.asyncio
async def test_get_extraction_unauthenticated(self, test_client: AsyncClient) -> None:
async def test_get_extraction_unauthenticated(
self, test_client: AsyncClient,
) -> None:
"""Test extraction retrieval without authentication."""
response = await test_client.get("/api/v1/sounds/extract/1")
@@ -46,7 +51,9 @@ class TestExtractionEndpoints:
@pytest.mark.asyncio
async def test_get_processor_status_moved_to_admin(
self, test_client: AsyncClient, admin_cookies: dict[str, str],
self,
test_client: AsyncClient,
admin_cookies: dict[str, str],
) -> None:
"""Test that processor status endpoint was moved to admin."""
# Set cookies on client instance to avoid deprecation warning
@@ -61,7 +68,9 @@ class TestExtractionEndpoints:
@pytest.mark.asyncio
async def test_get_user_extractions(
self, test_client: AsyncClient, auth_cookies: dict[str, str],
self,
test_client: AsyncClient,
auth_cookies: dict[str, str],
) -> None:
"""Test getting user extractions."""
# Set cookies on client instance to avoid deprecation warning

View File

@@ -1,6 +1,5 @@
"""Tests for playlist API endpoints."""
import pytest
import pytest_asyncio
from httpx import AsyncClient
@@ -348,7 +347,8 @@ class TestPlaylistEndpoints:
}
response = await authenticated_client.put(
f"/api/v1/playlists/{playlist_id}", json=payload,
f"/api/v1/playlists/{playlist_id}",
json=payload,
)
assert response.status_code == 200
@@ -386,7 +386,8 @@ class TestPlaylistEndpoints:
payload = {"name": "Updated Playlist", "description": "Updated description"}
response = await authenticated_client.put(
f"/api/v1/playlists/{playlist_id}", json=payload,
f"/api/v1/playlists/{playlist_id}",
json=payload,
)
assert response.status_code == 200
@@ -613,7 +614,8 @@ class TestPlaylistEndpoints:
payload = {"sound_id": sound_id}
response = await authenticated_client.post(
f"/api/v1/playlists/{playlist_id}/sounds", json=payload,
f"/api/v1/playlists/{playlist_id}/sounds",
json=payload,
)
assert response.status_code == 200
@@ -670,7 +672,8 @@ class TestPlaylistEndpoints:
payload = {"sound_id": sound_id, "position": 5}
response = await authenticated_client.post(
f"/api/v1/playlists/{playlist_id}/sounds", json=payload,
f"/api/v1/playlists/{playlist_id}/sounds",
json=payload,
)
assert response.status_code == 200
@@ -718,13 +721,15 @@ class TestPlaylistEndpoints:
# Add sound first time
response = await authenticated_client.post(
f"/api/v1/playlists/{playlist_id}/sounds", json=payload,
f"/api/v1/playlists/{playlist_id}/sounds",
json=payload,
)
assert response.status_code == 200
# Try to add same sound again
response = await authenticated_client.post(
f"/api/v1/playlists/{playlist_id}/sounds", json=payload,
f"/api/v1/playlists/{playlist_id}/sounds",
json=payload,
)
assert response.status_code == 400
assert "already in this playlist" in response.json()["detail"]
@@ -758,7 +763,8 @@ class TestPlaylistEndpoints:
payload = {"sound_id": 99999}
response = await authenticated_client.post(
f"/api/v1/playlists/{playlist_id}/sounds", json=payload,
f"/api/v1/playlists/{playlist_id}/sounds",
json=payload,
)
assert response.status_code == 404
@@ -806,7 +812,8 @@ class TestPlaylistEndpoints:
# Add sound first
payload = {"sound_id": sound_id}
await authenticated_client.post(
f"/api/v1/playlists/{playlist_id}/sounds", json=payload,
f"/api/v1/playlists/{playlist_id}/sounds",
json=payload,
)
# Remove sound
@@ -918,11 +925,15 @@ class TestPlaylistEndpoints:
# Reorder sounds - use positions that don't cause constraints
# When swapping, we need to be careful about unique constraints
payload = {
"sound_positions": [[sound1_id, 10], [sound2_id, 5]], # Use different positions to avoid constraints
"sound_positions": [
[sound1_id, 10],
[sound2_id, 5],
], # Use different positions to avoid constraints
}
response = await authenticated_client.put(
f"/api/v1/playlists/{playlist_id}/sounds/reorder", json=payload,
f"/api/v1/playlists/{playlist_id}/sounds/reorder",
json=payload,
)
assert response.status_code == 200

View File

@@ -158,7 +158,9 @@ class TestSocketEndpoints:
@pytest.mark.asyncio
async def test_send_message_missing_parameters(
self, authenticated_client: AsyncClient, authenticated_user: User,
self,
authenticated_client: AsyncClient,
authenticated_user: User,
) -> None:
"""Test sending message with missing parameters."""
# Missing target_user_id
@@ -177,7 +179,9 @@ class TestSocketEndpoints:
@pytest.mark.asyncio
async def test_broadcast_message_missing_parameters(
self, authenticated_client: AsyncClient, authenticated_user: User,
self,
authenticated_client: AsyncClient,
authenticated_user: User,
) -> None:
"""Test broadcasting message with missing parameters."""
response = await authenticated_client.post("/api/v1/socket/broadcast")
@@ -185,7 +189,9 @@ class TestSocketEndpoints:
@pytest.mark.asyncio
async def test_send_message_invalid_user_id(
self, authenticated_client: AsyncClient, authenticated_user: User,
self,
authenticated_client: AsyncClient,
authenticated_user: User,
) -> None:
"""Test sending message with invalid user ID."""
response = await authenticated_client.post(

View File

@@ -35,10 +35,10 @@ class TestSoundEndpoints:
with (
patch(
"app.services.extraction.ExtractionService.create_extraction"
"app.services.extraction.ExtractionService.create_extraction",
) as mock_create,
patch(
"app.services.extraction_processor.extraction_processor.queue_extraction"
"app.services.extraction_processor.extraction_processor.queue_extraction",
) as mock_queue,
):
mock_create.return_value = mock_extraction_info
@@ -53,7 +53,10 @@ class TestSoundEndpoints:
data = response.json()
assert data["message"] == "Extraction queued successfully"
assert data["extraction"]["id"] == 1
assert data["extraction"]["url"] == "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
assert (
data["extraction"]["url"]
== "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
)
@pytest.mark.asyncio
async def test_create_extraction_unauthenticated(self, client: AsyncClient) -> None:
@@ -75,7 +78,7 @@ class TestSoundEndpoints:
) -> None:
"""Test extraction creation with invalid URL."""
with patch(
"app.services.extraction.ExtractionService.create_extraction"
"app.services.extraction.ExtractionService.create_extraction",
) as mock_create:
mock_create.side_effect = ValueError("Invalid URL")
@@ -107,7 +110,7 @@ class TestSoundEndpoints:
}
with patch(
"app.services.extraction.ExtractionService.get_extraction_by_id"
"app.services.extraction.ExtractionService.get_extraction_by_id",
) as mock_get:
mock_get.return_value = mock_extraction_info
@@ -128,7 +131,7 @@ class TestSoundEndpoints:
) -> None:
"""Test getting non-existent extraction."""
with patch(
"app.services.extraction.ExtractionService.get_extraction_by_id"
"app.services.extraction.ExtractionService.get_extraction_by_id",
) as mock_get:
mock_get.return_value = None
@@ -169,7 +172,7 @@ class TestSoundEndpoints:
]
with patch(
"app.services.extraction.ExtractionService.get_user_extractions"
"app.services.extraction.ExtractionService.get_user_extractions",
) as mock_get:
mock_get.return_value = mock_extractions
@@ -202,7 +205,9 @@ class TestSoundEndpoints:
with (
patch("app.repositories.sound.SoundRepository.get_by_id") as mock_get_sound,
patch("app.services.credit.CreditService.validate_and_reserve_credits") as mock_validate,
patch(
"app.services.credit.CreditService.validate_and_reserve_credits",
) as mock_validate,
patch("app.services.vlc_player.VLCPlayerService.play_sound") as mock_play,
patch("app.services.credit.CreditService.deduct_credits") as mock_deduct,
):
@@ -227,7 +232,9 @@ class TestSoundEndpoints:
authenticated_user: User,
) -> None:
"""Test playing non-existent sound with VLC."""
with patch("app.repositories.sound.SoundRepository.get_by_id") as mock_get_sound:
with patch(
"app.repositories.sound.SoundRepository.get_by_id",
) as mock_get_sound:
mock_get_sound.return_value = None
response = await authenticated_client.post("/api/v1/sounds/play/999")
@@ -259,11 +266,14 @@ class TestSoundEndpoints:
with (
patch("app.repositories.sound.SoundRepository.get_by_id") as mock_get_sound,
patch("app.services.credit.CreditService.validate_and_reserve_credits") as mock_validate,
patch(
"app.services.credit.CreditService.validate_and_reserve_credits",
) as mock_validate,
):
mock_get_sound.return_value = mock_sound
mock_validate.side_effect = InsufficientCreditsError(
required=1, available=0
required=1,
available=0,
)
response = await authenticated_client.post("/api/v1/sounds/play/1")
@@ -286,7 +296,7 @@ class TestSoundEndpoints:
}
with patch(
"app.services.vlc_player.VLCPlayerService.stop_all_vlc_instances"
"app.services.vlc_player.VLCPlayerService.stop_all_vlc_instances",
) as mock_stop:
mock_stop.return_value = mock_result
@@ -295,4 +305,4 @@ class TestSoundEndpoints:
assert response.status_code == 200
data = response.json()
assert data["message"] == "All VLC instances stopped"
assert data["stopped_count"] == 3
assert data["stopped_count"] == 3