test: add tests for library structure detection in FSPlatformsHandler

This commit is contained in:
zurdi
2025-12-23 16:24:33 +00:00
parent 42487d4945
commit cbe64ce29c
2 changed files with 338 additions and 0 deletions

View File

@@ -1,8 +1,11 @@
from unittest.mock import patch
import pytest
from fastapi import status
from fastapi.testclient import TestClient
from main import app
from exceptions.fs_exceptions import PlatformAlreadyExistsException
from utils import get_version
@@ -68,3 +71,256 @@ def test_heartbeat_metadata(client):
def test_heartbeat_metadata_unknown_source(client):
response = client.get("/api/heartbeat/metadata/unknown")
assert response.status_code == status.HTTP_400_BAD_REQUEST
def test_get_setup_library_info_structure_a_detected(
self, client, admin_user, access_token
):
"""Test get_setup_library_info with Structure A detected"""
with patch(
"endpoints.heartbeat.fs_platform_handler.detect_library_structure"
) as mock_detect:
mock_detect.return_value = "A"
with patch(
"endpoints.heartbeat.fs_platform_handler.get_platforms"
) as mock_get_platforms:
mock_get_platforms.return_value = ["n64", "psx"]
with patch("os.path.exists", return_value=True):
with patch("os.listdir") as mock_listdir:
mock_listdir.side_effect = [
["game1.z64", "game2.z64"], # n64 roms
["game1.iso"], # psx roms
]
response = client.get(
"/api/setup/library",
headers={"Authorization": f"Bearer {access_token}"},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()
assert data["detected_structure"] == "A"
assert len(data["existing_platforms"]) == 2
assert data["existing_platforms"][0]["fs_slug"] == "n64"
assert data["existing_platforms"][0]["rom_count"] == 2
assert data["existing_platforms"][1]["fs_slug"] == "psx"
assert data["existing_platforms"][1]["rom_count"] == 1
assert "supported_platforms" in data
def test_get_setup_library_info_structure_b_detected(
self, client, admin_user, access_token
):
"""Test get_setup_library_info with Structure B detected"""
with patch(
"endpoints.heartbeat.fs_platform_handler.detect_library_structure"
) as mock_detect:
mock_detect.return_value = "B"
with patch(
"endpoints.heartbeat.fs_platform_handler.get_platforms"
) as mock_get_platforms:
mock_get_platforms.return_value = ["gba"]
with patch("os.path.exists", return_value=True):
with patch("os.listdir") as mock_listdir:
mock_listdir.return_value = ["game1.gba", "game2.gba", "game3.gba"]
response = client.get(
"/api/setup/library",
headers={"Authorization": f"Bearer {access_token}"},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()
assert data["detected_structure"] == "B"
assert len(data["existing_platforms"]) == 1
assert data["existing_platforms"][0]["fs_slug"] == "gba"
assert data["existing_platforms"][0]["rom_count"] == 3
def test_get_setup_library_info_no_structure_detected(
self, client, admin_user, access_token
):
"""Test get_setup_library_info when no structure is detected"""
with patch(
"endpoints.heartbeat.fs_platform_handler.detect_library_structure"
) as mock_detect:
mock_detect.return_value = None
with patch(
"endpoints.heartbeat.fs_platform_handler.get_platforms"
) as mock_get_platforms:
mock_get_platforms.return_value = []
response = client.get(
"/api/setup/library",
headers={"Authorization": f"Bearer {access_token}"},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()
assert data["detected_structure"] is None
assert data["existing_platforms"] == []
assert "supported_platforms" in data
def test_get_setup_library_info_handles_errors(self, client, admin_user, access_token):
"""Test get_setup_library_info handles filesystem errors gracefully"""
with patch(
"endpoints.heartbeat.fs_platform_handler.detect_library_structure"
) as mock_detect:
mock_detect.return_value = "A"
with patch(
"endpoints.heartbeat.fs_platform_handler.get_platforms"
) as mock_get_platforms:
# Simulate error retrieving platforms
mock_get_platforms.side_effect = Exception("Filesystem error")
response = client.get(
"/api/setup/library",
headers={"Authorization": f"Bearer {access_token}"},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()
# Should return empty platforms list on error
assert data["existing_platforms"] == []
def test_create_setup_platforms_success(self, client, admin_user, access_token):
"""Test create_setup_platforms successfully creates platforms"""
platform_slugs = ["n64", "psx", "gba"]
with patch(
"endpoints.heartbeat.fs_platform_handler.detect_library_structure"
) as mock_detect:
mock_detect.return_value = "A"
with patch(
"endpoints.heartbeat.fs_platform_handler.add_platform"
) as mock_add_platform:
mock_add_platform.return_value = None # Successful creation
response = client.post(
"/api/setup/platforms",
json=platform_slugs,
headers={"Authorization": f"Bearer {access_token}"},
)
assert response.status_code == status.HTTP_201_CREATED
data = response.json()
assert data["success"] is True
assert data["created_count"] == 3
assert "Successfully created 3 platform folder(s)" in data["message"]
assert mock_add_platform.call_count == 3
def test_create_setup_platforms_empty_list(self, client, admin_user, access_token):
"""Test create_setup_platforms with empty platform list"""
response = client.post(
"/api/setup/platforms",
json=[],
headers={"Authorization": f"Bearer {access_token}"},
)
assert response.status_code == status.HTTP_201_CREATED
data = response.json()
assert data["success"] is True
assert data["created_count"] == 0
assert data["message"] == "No platforms selected"
def test_create_setup_platforms_creates_structure_a_when_none_exists(
self, client, admin_user, access_token
):
"""Test create_setup_platforms creates Structure A when no structure detected"""
platform_slugs = ["n64"]
with patch(
"endpoints.heartbeat.fs_platform_handler.detect_library_structure"
) as mock_detect:
mock_detect.return_value = None # No structure detected
with patch("os.makedirs") as mock_makedirs:
with patch("endpoints.heartbeat.fs_platform_handler.add_platform"):
response = client.post(
"/api/setup/platforms",
json=platform_slugs,
headers={"Authorization": f"Bearer {access_token}"},
)
assert response.status_code == status.HTTP_201_CREATED
# Should create roms folder first
mock_makedirs.assert_called_once()
assert "roms" in str(mock_makedirs.call_args[0][0])
def test_create_setup_platforms_skips_existing_platforms(
self, client, admin_user, access_token
):
"""Test create_setup_platforms skips platforms that already exist"""
platform_slugs = ["n64", "psx", "gba"]
with patch(
"endpoints.heartbeat.fs_platform_handler.detect_library_structure"
) as mock_detect:
mock_detect.return_value = "A"
with patch(
"endpoints.heartbeat.fs_platform_handler.add_platform"
) as mock_add_platform:
# First platform already exists, second succeeds, third succeeds
mock_add_platform.side_effect = [
PlatformAlreadyExistsException("n64"),
None,
None,
]
response = client.post(
"/api/setup/platforms",
json=platform_slugs,
headers={"Authorization": f"Bearer {access_token}"},
)
assert response.status_code == status.HTTP_201_CREATED
data = response.json()
assert data["success"] is True
# Should only count 2 created (psx and gba)
assert data["created_count"] == 2
def test_create_setup_platforms_handles_permission_errors(
self, client, admin_user, access_token
):
"""Test create_setup_platforms handles permission errors"""
platform_slugs = ["n64"]
with patch(
"endpoints.heartbeat.fs_platform_handler.detect_library_structure"
) as mock_detect:
mock_detect.return_value = "A"
with patch(
"endpoints.heartbeat.fs_platform_handler.add_platform"
) as mock_add_platform:
mock_add_platform.side_effect = PermissionError("Permission denied")
response = client.post(
"/api/setup/platforms",
json=platform_slugs,
headers={"Authorization": f"Bearer {access_token}"},
)
assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR
assert "Failed to create some platform folders" in response.json()["detail"]

View File

@@ -311,3 +311,85 @@ class TestFSPlatformsHandler:
for platform in expected_filtered:
structure = handler.get_platform_fs_structure(platform)
assert structure == f"{platform}/{config.ROMS_FOLDER_NAME}"
def test_detect_library_structure_structure_a(
self, handler: FSPlatformsHandler, config
):
"""Test detect_library_structure detects Structure A (roms/{platform})"""
roms_path = f"{LIBRARY_BASE_PATH}/{config.ROMS_FOLDER_NAME}"
with patch(
"handler.filesystem.platforms_handler.cm.get_config", return_value=config
):
with patch("os.path.exists") as mock_exists:
mock_exists.return_value = True
result = handler.detect_library_structure()
assert result == "A"
mock_exists.assert_called_once_with(roms_path)
def test_detect_library_structure_structure_b(
self, handler: FSPlatformsHandler, config
):
"""Test detect_library_structure detects Structure B ({platform}/roms)"""
with patch(
"handler.filesystem.platforms_handler.cm.get_config", return_value=config
):
with patch("os.path.exists") as mock_exists:
# Roms folder doesn't exist at base level
mock_exists.return_value = False
with patch("os.listdir") as mock_listdir:
mock_listdir.return_value = ["n64", "psx", "other_folder"]
with patch("os.path.isdir") as mock_isdir:
# n64 and psx are directories with roms subfolders
def isdir_side_effect(path):
return "n64" in path or "psx" in path
def exists_side_effect(path):
# n64/roms and psx/roms exist
return (
f"n64/{config.ROMS_FOLDER_NAME}" in path
or f"psx/{config.ROMS_FOLDER_NAME}" in path
)
mock_isdir.side_effect = isdir_side_effect
mock_exists.side_effect = exists_side_effect
result = handler.detect_library_structure()
assert result == "B"
def test_detect_library_structure_none(self, handler: FSPlatformsHandler, config):
"""Test detect_library_structure returns None when no structure detected"""
with patch(
"handler.filesystem.platforms_handler.cm.get_config", return_value=config
):
with patch("os.path.exists", return_value=False):
with patch("os.listdir", return_value=[]):
result = handler.detect_library_structure()
assert result is None
def test_detect_library_structure_handles_os_errors(
self, handler: FSPlatformsHandler, config
):
"""Test detect_library_structure handles OS errors gracefully"""
with patch(
"handler.filesystem.platforms_handler.cm.get_config", return_value=config
):
with patch("os.path.exists", return_value=False):
with patch("os.listdir", side_effect=OSError("Permission denied")):
result = handler.detect_library_structure()
assert result is None
def test_detect_library_structure_empty_library(
self, handler: FSPlatformsHandler, config
):
"""Test detect_library_structure with empty library directory"""
with patch(
"handler.filesystem.platforms_handler.cm.get_config", return_value=config
):
with patch("os.path.exists", return_value=False):
with patch("os.listdir", return_value=[]):
result = handler.detect_library_structure()
assert result is None