diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 266c878a1..8fd8d301f 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -29,6 +29,12 @@ jobs: MYSQL_DATABASE: romm_test MYSQL_ROOT_PASSWORD: passwd options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 + valkey: + image: valkey/valkey:7.2 + ports: + - 6379 + options: >- + --health-cmd="redis-cli ping" --health-interval=5s --health-timeout=2s --health-retries=3 steps: - name: Checkout repository uses: actions/checkout@v4.3.0 @@ -57,6 +63,8 @@ jobs: env: DB_HOST: 127.0.0.1 DB_PORT: ${{ job.services.mariadb.ports['3306'] }} + REDIS_HOST: 127.0.0.1 + REDIS_PORT: ${{ job.services.valkey.ports['6379'] }} run: | cd backend uv run pytest -vv --maxfail=10 --junitxml=pytest-report.xml --cov --cov-report xml:coverage.xml --cov-config=.coveragerc . diff --git a/backend/tasks/tasks.py b/backend/tasks/tasks.py index 6d6345e94..076de6726 100644 --- a/backend/tasks/tasks.py +++ b/backend/tasks/tasks.py @@ -1,5 +1,6 @@ from abc import ABC, abstractmethod from enum import Enum +from itertools import chain from typing import Any import httpx @@ -77,7 +78,7 @@ class PeriodicTask(Task, ABC): self.func = func def _get_existing_job(self) -> Job | None: - existing_jobs = tasks_scheduler.get_jobs() + existing_jobs = chain(tasks_scheduler.get_jobs(), low_prio_queue.get_jobs()) for job in existing_jobs: if isinstance(job, Job) and get_job_func_name(job) == self.func: return job diff --git a/backend/tests/tasks/test_prevent_requeue.py b/backend/tests/tasks/test_prevent_requeue.py new file mode 100644 index 000000000..da31f0ddf --- /dev/null +++ b/backend/tests/tasks/test_prevent_requeue.py @@ -0,0 +1,48 @@ +import unittest +from unittest.mock import MagicMock, patch + +from rq.job import Job + +from tasks.tasks import PeriodicTask, TaskType + + +def dummy_task(): + pass + + +class TestTask(PeriodicTask): + async def run(self, *args, **kwargs): + pass + + +class TestPreventRequeue(unittest.TestCase): + @patch("tasks.tasks.tasks_scheduler") + @patch("tasks.tasks.low_prio_queue") + def test_task_not_scheduled_if_in_queue( + self, mock_low_prio_queue, mock_tasks_scheduler + ): + for method_name in ["init", "schedule"]: + with self.subTest(method=method_name): + task = TestTask( + title="Test Task", + description="A test task", + task_type=TaskType.GENERIC, + enabled=True, + manual_run=False, + cron_string="* * * * *", + func="backend.tests.tasks.test_prevent_requeue.dummy_task", + ) + + mock_job = MagicMock(spec=Job) + mock_job.func_name = ( + "backend.tests.tasks.test_prevent_requeue.dummy_task" + ) + + mock_low_prio_queue.get_jobs.return_value = [mock_job] + mock_tasks_scheduler.get_jobs.return_value = [] + + method_to_call = getattr(task, method_name) + result = method_to_call() + + self.assertIsNone(result) + mock_tasks_scheduler.cron.assert_not_called() diff --git a/backend/tests/tasks/test_scan_library.py b/backend/tests/tasks/test_scan_library.py index f9876a11f..54be8feec 100644 --- a/backend/tests/tasks/test_scan_library.py +++ b/backend/tests/tasks/test_scan_library.py @@ -2,13 +2,16 @@ from unittest.mock import AsyncMock, MagicMock import pytest +from handler.metadata.flashpoint_handler import FlashpointHandler from handler.metadata.hasheous_handler import HasheousHandler +from handler.metadata.hltb_handler import HLTBHandler from handler.metadata.igdb_handler import IGDBHandler from handler.metadata.launchbox_handler import LaunchboxHandler from handler.metadata.moby_handler import MobyGamesHandler from handler.metadata.ra_handler import RAHandler from handler.metadata.sgdb_handler import SGDBBaseHandler from handler.metadata.ss_handler import SSHandler +from handler.metadata.tgdb_handler import TGDBHandler from handler.scan_handler import MetadataSource, ScanType from tasks.scheduled.scan_library import ScanLibraryTask, scan_library_task @@ -32,6 +35,9 @@ class TestScanLibraryTask: mocker.patch.object(RAHandler, "is_enabled", return_value=True) mocker.patch.object(SGDBBaseHandler, "is_enabled", return_value=False) mocker.patch.object(SSHandler, "is_enabled", return_value=False) + mocker.patch.object(FlashpointHandler, "is_enabled", return_value=False) + mocker.patch.object(HLTBHandler, "is_enabled", return_value=False) + mocker.patch.object(TGDBHandler, "is_enabled", return_value=False) mocker.patch("tasks.scheduled.scan_library.ENABLE_SCHEDULED_RESCAN", True) mock_scan_platforms = mocker.patch( "tasks.scheduled.scan_library.scan_platforms"