fix: isolate tests from production database

Tests that imported wled_controller.main at module level caused the real
production database (data/ledgrab.db) to be opened before test fixtures
could patch the config. This led to silent data loss.

Patch the global config singleton at conftest module level (before any
test imports main.py) to redirect all DB access to a temp directory.
This commit is contained in:
2026-04-01 19:01:56 +03:00
parent 6b0e4e5539
commit 992495e2e4
3 changed files with 79 additions and 24 deletions
+57 -11
View File
@@ -1,20 +1,52 @@
"""Pytest configuration and shared fixtures."""
"""Pytest configuration and shared fixtures.
IMPORTANT: This conftest patches the global config singleton BEFORE any test
module can import ``wled_controller.main``. ``main.py`` reads ``get_config()``
at module level to open the database — if the singleton is not patched first,
the REAL production database (``data/ledgrab.db``) is opened and tests
read/write/delete production data.
"""
import tempfile
from datetime import datetime, timezone
from pathlib import Path
import pytest
from wled_controller.config import Config, StorageConfig, ServerConfig, AuthConfig
from wled_controller.storage.database import Database
from wled_controller.storage.device_store import Device, DeviceStore
from wled_controller.storage.sync_clock import SyncClock
from wled_controller.storage.sync_clock_store import SyncClockStore
from wled_controller.storage.output_target_store import OutputTargetStore
from wled_controller.storage.automation import (
Automation,
# ---------------------------------------------------------------------------
# ISOLATE ALL TESTS FROM PRODUCTION DATA — must happen before any test module
# imports ``wled_controller.main``.
# ---------------------------------------------------------------------------
import wled_controller.config as _config_mod # noqa: E402
_test_tmp = Path(tempfile.mkdtemp(prefix="wled_test_"))
_test_db_path = str(_test_tmp / "test_ledgrab.db")
_test_assets_dir = str(_test_tmp / "test_assets")
_original_config = _config_mod.Config.load()
_test_config = _original_config.model_copy(
update={
"storage": _config_mod.StorageConfig(database_file=_test_db_path),
"assets": _config_mod.AssetsConfig(
assets_dir=_test_assets_dir,
max_file_size_mb=_original_config.assets.max_file_size_mb,
),
},
)
from wled_controller.storage.automation_store import AutomationStore
from wled_controller.storage.value_source_store import ValueSourceStore
_config_mod.config = _test_config
# ---------------------------------------------------------------------------
from wled_controller.config import Config, StorageConfig, ServerConfig, AuthConfig # noqa: E402
from wled_controller.storage.database import Database # noqa: E402
from wled_controller.storage.device_store import Device, DeviceStore # noqa: E402
from wled_controller.storage.sync_clock import SyncClock # noqa: E402
from wled_controller.storage.sync_clock_store import SyncClockStore # noqa: E402
from wled_controller.storage.output_target_store import OutputTargetStore # noqa: E402
from wled_controller.storage.automation import Automation # noqa: E402
from wled_controller.storage.automation_store import AutomationStore # noqa: E402
from wled_controller.storage.value_source_store import ValueSourceStore # noqa: E402
# ---------------------------------------------------------------------------
@@ -242,3 +274,17 @@ def sample_calibration():
{"edge": "left", "led_start": 110, "led_count": 40, "reverse": True},
],
}
# ---------------------------------------------------------------------------
# Session cleanup — remove temporary test directory
# ---------------------------------------------------------------------------
@pytest.fixture(scope="session", autouse=True)
def _cleanup_test_tmp():
"""Remove the temporary test directory after all tests complete."""
import shutil
yield
shutil.rmtree(_test_tmp, ignore_errors=True)