Files
HappyOnigiri-ComfyUI-Meld/tests/test_database_manager.py
T
HappyOnigiri 74fa31d519 test: update existing tests and add ScanState unit tests for thread-safe API
Replace direct attribute mutation (_scan_state.should_cancel = True/False,
set_scan_running calls) with ScanState methods (request_cancel, mark_finished,
try_start). Add test_scan_state.py covering try_start double-start prevention,
mark_finished reset, get_status snapshot isolation, and counter accessors.
2026-03-31 08:50:19 +09:00

148 lines
6.6 KiB
Python

import os
import shutil
import sys
import tempfile
import unittest
from typing import Any
from unittest.mock import MagicMock, patch
_MOCK_KEYS = (
"folder_paths",
"server",
"comfy.cli_args",
"nodes",
"comfy",
"comfy.sd",
"comfy.utils",
"comfy.samplers",
)
for k in _MOCK_KEYS:
if k not in sys.modules:
sys.modules[k] = MagicMock()
import meld.image_manager.common.db.client as client # noqa: E402
import meld.image_manager.common.db.runtime_state as runtime_state # noqa: E402
import meld.image_manager.common.db.schema as schema # noqa: E402
import meld.image_manager.features.databases.service as database_service # noqa: E402
import meld.image_manager.features.importer.service as importer_service # noqa: E402
from meld.image_manager.common.exceptions import ConflictError # noqa: E402
class TestDatabaseManager(unittest.TestCase):
def setUp(self) -> None:
self.test_dir = tempfile.mkdtemp()
self.databases_dir = os.path.join(self.test_dir, "databases")
self.runtime_root_dir = os.path.join(self.test_dir, "runtime")
self.active_state_path = os.path.join(self.test_dir, "active_database.json")
self.legacy_default_db_path = os.path.join(self.test_dir, "default.db")
os.makedirs(self.databases_dir, exist_ok=True)
os.makedirs(self.runtime_root_dir, exist_ok=True)
self.patchers: list[Any] = [
patch.object(client, "DATA_DIR", self.test_dir),
patch.object(client, "DATABASES_DIR", self.databases_dir),
patch.object(client, "RUNTIME_ROOT_DIR", self.runtime_root_dir),
patch.object(client, "ACTIVE_DATABASE_STATE_PATH", self.active_state_path),
patch.object(client, "LEGACY_DEFAULT_DB_PATH", self.legacy_default_db_path),
patch.object(client, "DB_PATH", self.legacy_default_db_path),
patch.object(client, "TRASH_DIR", os.path.join(self.runtime_root_dir, "default", "trash")),
patch.object(
client,
"THUMBNAIL_CACHE_DIR",
os.path.join(self.runtime_root_dir, "default", "thumbnails"),
),
patch.object(client, "ACTIVE_DATABASE_NAME", client.DEFAULT_DATABASE_NAME),
patch.object(client, "ACTIVE_DATABASE_GENERATION", 0),
]
for patcher in self.patchers:
patcher.start()
runtime_state.set_startup_cleanup_running(False)
runtime_state.set_analytics_refresh_running(False)
importer_service._scan_state.mark_finished()
client.refresh_active_database_state()
schema.init_db()
def tearDown(self) -> None:
importer_service._scan_state.mark_finished()
runtime_state.set_startup_cleanup_running(False)
runtime_state.set_analytics_refresh_running(False)
for patcher in reversed(self.patchers):
patcher.stop()
shutil.rmtree(self.test_dir)
def test_create_database_without_switch_keeps_active_database(self) -> None:
payload = database_service.create_database_and_get_payload("project_a", False)
self.assertEqual(payload["active_database"], "default")
self.assertEqual(payload["database_generation"], 0)
self.assertTrue(os.path.exists(os.path.join(self.databases_dir, "project_a.db")))
self.assertEqual(sorted(db["name"] for db in payload["databases"]), ["default", "project_a"])
def test_switch_database_updates_active_state_and_generation(self) -> None:
database_service.create_database_and_get_payload("project_a", False)
payload = database_service.switch_database_and_get_payload("project_a")
self.assertEqual(payload["active_database"], "project_a")
self.assertEqual(payload["database_generation"], 1)
self.assertEqual(client.get_active_database_state().name, "project_a")
self.assertTrue(client.DB_PATH.endswith("project_a.db"))
def test_delete_active_database_switches_to_fallback(self) -> None:
database_service.create_database_and_get_payload("project_a", False)
database_service.switch_database_and_get_payload("project_a")
payload = database_service.delete_database_and_get_payload("project_a")
self.assertEqual(payload["active_database"], "default")
self.assertFalse(os.path.exists(os.path.join(self.databases_dir, "project_a.db")))
def test_rename_inactive_database_moves_db_and_runtime(self) -> None:
database_service.create_database_and_get_payload("project_a", False)
os.makedirs(client.get_database_runtime_dir("project_a"), exist_ok=True)
payload = database_service.rename_database_and_get_payload("project_a", "project_b")
self.assertTrue(os.path.exists(os.path.join(self.databases_dir, "project_b.db")))
self.assertFalse(os.path.exists(os.path.join(self.databases_dir, "project_a.db")))
self.assertTrue(os.path.isdir(client.get_database_runtime_dir("project_b")))
self.assertIn("project_b", [db["name"] for db in payload["databases"]])
def test_rename_active_database_updates_active_state(self) -> None:
payload = database_service.rename_database_and_get_payload("default", "renamed_default")
self.assertEqual(payload["active_database"], "renamed_default")
self.assertEqual(client.get_active_database_state().name, "renamed_default")
self.assertTrue(os.path.exists(client.get_database_path("renamed_default")))
def test_delete_last_default_recreates_empty_default_database(self) -> None:
payload = database_service.delete_database_and_get_payload("default")
self.assertEqual(payload["active_database"], "default")
self.assertTrue(os.path.exists(client.get_database_path("default")))
self.assertGreaterEqual(payload["database_generation"], 1)
def test_switch_is_blocked_while_scan_is_running(self) -> None:
database_service.create_database_and_get_payload("project_a", False)
importer_service._scan_state.try_start()
try:
with self.assertRaises(ConflictError):
database_service.switch_database_and_get_payload("project_a")
finally:
importer_service._scan_state.mark_finished()
def test_switch_is_blocked_while_analytics_refresh_is_running(self) -> None:
database_service.create_database_and_get_payload("project_a", False)
runtime_state.set_analytics_refresh_running(True)
try:
with self.assertRaises(ConflictError):
database_service.switch_database_and_get_payload("project_a")
finally:
runtime_state.set_analytics_refresh_running(False)
if __name__ == "__main__":
unittest.main()