mirror of
https://github.com/rommapp/romm.git
synced 2026-05-04 00:01:30 +08:00
327 lines
12 KiB
Python
327 lines
12 KiB
Python
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
|
|
from adapters.services.retroachievements_types import RAUserCompletionProgressKind
|
|
from handler.database.roms_handler import DBRomsHandler
|
|
from handler.database.users_handler import DBUsersHandler
|
|
from handler.metadata.ra_handler import RAHandler
|
|
from models.rom import RomUser, RomUserStatus
|
|
from tasks.scheduled.sync_retroachievements_progress import (
|
|
SyncRetroAchievementsProgressTask,
|
|
_get_rom_user_status_from_ra_award_kind,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def task() -> SyncRetroAchievementsProgressTask:
|
|
"""Create a task instance for testing."""
|
|
return SyncRetroAchievementsProgressTask()
|
|
|
|
|
|
class TestGetRomUserStatusFromRaAwardKind:
|
|
"""Tests for the _get_rom_user_status_from_ra_award_kind helper."""
|
|
|
|
def test_mastered_returns_completed_100(self):
|
|
assert (
|
|
_get_rom_user_status_from_ra_award_kind(
|
|
RAUserCompletionProgressKind.MASTERED
|
|
)
|
|
== RomUserStatus.COMPLETED_100
|
|
)
|
|
|
|
def test_completed_returns_completed_100(self):
|
|
assert (
|
|
_get_rom_user_status_from_ra_award_kind(
|
|
RAUserCompletionProgressKind.COMPLETED
|
|
)
|
|
== RomUserStatus.COMPLETED_100
|
|
)
|
|
|
|
def test_beaten_hardcore_returns_finished(self):
|
|
assert (
|
|
_get_rom_user_status_from_ra_award_kind(
|
|
RAUserCompletionProgressKind.BEATEN_HARDCORE
|
|
)
|
|
== RomUserStatus.FINISHED
|
|
)
|
|
|
|
def test_beaten_softcore_returns_finished(self):
|
|
assert (
|
|
_get_rom_user_status_from_ra_award_kind(
|
|
RAUserCompletionProgressKind.BEATEN_SOFTCORE
|
|
)
|
|
== RomUserStatus.FINISHED
|
|
)
|
|
|
|
def test_none_returns_incomplete(self):
|
|
assert _get_rom_user_status_from_ra_award_kind(None) == RomUserStatus.INCOMPLETE
|
|
|
|
def test_unknown_value_returns_none(self):
|
|
assert _get_rom_user_status_from_ra_award_kind("unknown_award") is None
|
|
|
|
|
|
class TestSyncRetroAchievementsProgressTask:
|
|
"""Test suite for SyncRetroAchievementsProgressTask."""
|
|
|
|
def test_task_initialization(self, task):
|
|
"""Test task initialization with correct parameters."""
|
|
assert (
|
|
task.func
|
|
== "tasks.scheduled.sync_retroachievements_progress.sync_retroachievements_progress_task.run"
|
|
)
|
|
assert task.description == "Updates RetroAchievements progress for all users"
|
|
|
|
async def test_run_when_retroachievements_api_disabled(self, task, mocker):
|
|
"""Test run method when RetroAchievements API is disabled."""
|
|
mocker.patch.object(RAHandler, "is_enabled", return_value=False)
|
|
mock_log = mocker.patch("tasks.scheduled.sync_retroachievements_progress.log")
|
|
|
|
await task.run()
|
|
|
|
mock_log.warning.assert_called_once_with(
|
|
"RetroAchievements API is not enabled, skipping progress sync"
|
|
)
|
|
|
|
async def test_run_when_no_users_set(self, task, mocker):
|
|
"""Test run method when no users have RetroAchievements usernames set"""
|
|
mock_get_users = mocker.patch.object(
|
|
DBUsersHandler, "get_users", return_value=[]
|
|
)
|
|
mock_get_user_progression = mocker.patch.object(
|
|
RAHandler, "get_user_progression"
|
|
)
|
|
|
|
await task.run()
|
|
|
|
mock_get_users.assert_called_once_with(has_ra_username=True)
|
|
mock_get_user_progression.assert_not_called()
|
|
|
|
async def test_run_saves_progress(self, task, viewer_user, mocker):
|
|
"""Test run method saves retrieved progress."""
|
|
mocker.patch.object(DBUsersHandler, "get_users", return_value=[viewer_user])
|
|
mock_update_user = mocker.patch.object(DBUsersHandler, "update_user")
|
|
user_progression = {"total": 0, "results": []}
|
|
mocker.patch.object(
|
|
RAHandler, "get_user_progression", return_value=user_progression
|
|
)
|
|
|
|
await task.run()
|
|
|
|
mock_update_user.assert_called_once_with(
|
|
viewer_user.id,
|
|
{"ra_progression": user_progression},
|
|
)
|
|
|
|
async def test_run_is_resilient_to_errors(
|
|
self, task, viewer_user, editor_user, mocker
|
|
):
|
|
"""Test run method saves retrieved progress for a user even if another user fails."""
|
|
mocker.patch.object(
|
|
DBUsersHandler, "get_users", return_value=[viewer_user, editor_user]
|
|
)
|
|
user_progression = {"total": 0, "results": []}
|
|
mocker.patch.object(
|
|
RAHandler,
|
|
"get_user_progression",
|
|
side_effect=[
|
|
# Call for first user raises an exception.
|
|
Exception("API error"),
|
|
# Call for second user returns valid progression.
|
|
user_progression,
|
|
],
|
|
)
|
|
mock_update_user = mocker.patch.object(DBUsersHandler, "update_user")
|
|
|
|
await task.run()
|
|
|
|
mock_update_user.assert_called_once_with(
|
|
editor_user.id,
|
|
{"ra_progression": user_progression},
|
|
)
|
|
|
|
async def test_run_sets_rom_user_status_when_unset(
|
|
self, task, viewer_user, rom, mocker
|
|
):
|
|
"""Test that rom_user.status is set from RA award kind when currently unset."""
|
|
ra_id = 12345
|
|
mocker.patch.object(DBUsersHandler, "get_users", return_value=[viewer_user])
|
|
mocker.patch.object(DBUsersHandler, "update_user")
|
|
user_progression = {
|
|
"total": 1,
|
|
"results": [
|
|
{
|
|
"rom_ra_id": ra_id,
|
|
"max_possible": 50,
|
|
"num_awarded": 50,
|
|
"num_awarded_hardcore": 50,
|
|
"highest_award_kind": RAUserCompletionProgressKind.MASTERED,
|
|
"earned_achievements": [],
|
|
}
|
|
],
|
|
}
|
|
mocker.patch.object(
|
|
RAHandler, "get_user_progression", return_value=user_progression
|
|
)
|
|
mock_rom = MagicMock()
|
|
mock_rom.id = rom.id
|
|
mocker.patch.object(
|
|
DBRomsHandler, "get_rom_by_metadata_id", return_value=mock_rom
|
|
)
|
|
mock_rom_user = MagicMock(spec=RomUser)
|
|
mock_rom_user.id = 1
|
|
mock_rom_user.status = None
|
|
mocker.patch.object(DBRomsHandler, "get_rom_user", return_value=mock_rom_user)
|
|
mock_update_rom_user = mocker.patch.object(DBRomsHandler, "update_rom_user")
|
|
|
|
await task.run()
|
|
|
|
mock_update_rom_user.assert_called_once_with(
|
|
mock_rom_user.id, {"status": RomUserStatus.COMPLETED_100}
|
|
)
|
|
|
|
async def test_run_updates_existing_rom_user_status_when_changed(
|
|
self, task, viewer_user, rom, mocker
|
|
):
|
|
"""Test that rom_user.status is updated when the RA award kind changes."""
|
|
ra_id = 12345
|
|
mocker.patch.object(DBUsersHandler, "get_users", return_value=[viewer_user])
|
|
mocker.patch.object(DBUsersHandler, "update_user")
|
|
user_progression = {
|
|
"total": 1,
|
|
"results": [
|
|
{
|
|
"rom_ra_id": ra_id,
|
|
"max_possible": 50,
|
|
"num_awarded": 50,
|
|
"num_awarded_hardcore": 50,
|
|
"highest_award_kind": RAUserCompletionProgressKind.MASTERED,
|
|
"earned_achievements": [],
|
|
}
|
|
],
|
|
}
|
|
mocker.patch.object(
|
|
RAHandler, "get_user_progression", return_value=user_progression
|
|
)
|
|
mock_rom = MagicMock()
|
|
mock_rom.id = rom.id
|
|
mocker.patch.object(
|
|
DBRomsHandler, "get_rom_by_metadata_id", return_value=mock_rom
|
|
)
|
|
mock_rom_user = MagicMock(spec=RomUser)
|
|
mock_rom_user.id = 1
|
|
# Previously INCOMPLETE (set by an earlier sync), now mastered in RA
|
|
mock_rom_user.status = RomUserStatus.INCOMPLETE
|
|
mocker.patch.object(DBRomsHandler, "get_rom_user", return_value=mock_rom_user)
|
|
mock_update_rom_user = mocker.patch.object(DBRomsHandler, "update_rom_user")
|
|
|
|
await task.run()
|
|
|
|
mock_update_rom_user.assert_called_once_with(
|
|
mock_rom_user.id, {"status": RomUserStatus.COMPLETED_100}
|
|
)
|
|
|
|
async def test_run_skips_update_when_status_already_matches(
|
|
self, task, viewer_user, rom, mocker
|
|
):
|
|
"""Test that rom_user.status is not written again when it already matches RA."""
|
|
ra_id = 12345
|
|
mocker.patch.object(DBUsersHandler, "get_users", return_value=[viewer_user])
|
|
mocker.patch.object(DBUsersHandler, "update_user")
|
|
user_progression = {
|
|
"total": 1,
|
|
"results": [
|
|
{
|
|
"rom_ra_id": ra_id,
|
|
"max_possible": 50,
|
|
"num_awarded": 50,
|
|
"num_awarded_hardcore": 50,
|
|
"highest_award_kind": RAUserCompletionProgressKind.MASTERED,
|
|
"earned_achievements": [],
|
|
}
|
|
],
|
|
}
|
|
mocker.patch.object(
|
|
RAHandler, "get_user_progression", return_value=user_progression
|
|
)
|
|
mock_rom = MagicMock()
|
|
mock_rom.id = rom.id
|
|
mocker.patch.object(
|
|
DBRomsHandler, "get_rom_by_metadata_id", return_value=mock_rom
|
|
)
|
|
mock_rom_user = MagicMock(spec=RomUser)
|
|
mock_rom_user.id = 1
|
|
mock_rom_user.status = RomUserStatus.COMPLETED_100 # Already up-to-date
|
|
mocker.patch.object(DBRomsHandler, "get_rom_user", return_value=mock_rom_user)
|
|
mock_update_rom_user = mocker.patch.object(DBRomsHandler, "update_rom_user")
|
|
|
|
await task.run()
|
|
|
|
mock_update_rom_user.assert_not_called()
|
|
|
|
async def test_run_sets_incomplete_status_for_started_games(
|
|
self, task, viewer_user, rom, mocker
|
|
):
|
|
"""Test that INCOMPLETE status is set for games started but not beaten in RA."""
|
|
ra_id = 99999
|
|
mocker.patch.object(DBUsersHandler, "get_users", return_value=[viewer_user])
|
|
mocker.patch.object(DBUsersHandler, "update_user")
|
|
user_progression = {
|
|
"total": 1,
|
|
"results": [
|
|
{
|
|
"rom_ra_id": ra_id,
|
|
"max_possible": 100,
|
|
"num_awarded": 10,
|
|
"num_awarded_hardcore": 0,
|
|
"highest_award_kind": None,
|
|
"earned_achievements": [],
|
|
}
|
|
],
|
|
}
|
|
mocker.patch.object(
|
|
RAHandler, "get_user_progression", return_value=user_progression
|
|
)
|
|
mock_rom = MagicMock()
|
|
mock_rom.id = rom.id
|
|
mocker.patch.object(
|
|
DBRomsHandler, "get_rom_by_metadata_id", return_value=mock_rom
|
|
)
|
|
mock_rom_user = MagicMock(spec=RomUser)
|
|
mock_rom_user.id = 1
|
|
mock_rom_user.status = None
|
|
mocker.patch.object(DBRomsHandler, "get_rom_user", return_value=mock_rom_user)
|
|
mock_update_rom_user = mocker.patch.object(DBRomsHandler, "update_rom_user")
|
|
|
|
await task.run()
|
|
|
|
mock_update_rom_user.assert_called_once_with(
|
|
mock_rom_user.id, {"status": RomUserStatus.INCOMPLETE}
|
|
)
|
|
|
|
async def test_run_skips_status_update_when_rom_not_found(
|
|
self, task, viewer_user, mocker
|
|
):
|
|
"""Test that status update is skipped when the ROM is not in the database."""
|
|
mocker.patch.object(DBUsersHandler, "get_users", return_value=[viewer_user])
|
|
mocker.patch.object(DBUsersHandler, "update_user")
|
|
user_progression = {
|
|
"total": 1,
|
|
"results": [
|
|
{
|
|
"rom_ra_id": 99999,
|
|
"highest_award_kind": RAUserCompletionProgressKind.MASTERED,
|
|
"earned_achievements": [],
|
|
}
|
|
],
|
|
}
|
|
mocker.patch.object(
|
|
RAHandler, "get_user_progression", return_value=user_progression
|
|
)
|
|
mocker.patch.object(DBRomsHandler, "get_rom_by_metadata_id", return_value=None)
|
|
mock_update_rom_user = mocker.patch.object(DBRomsHandler, "update_rom_user")
|
|
|
|
await task.run()
|
|
|
|
mock_update_rom_user.assert_not_called()
|