discord-rss-bot/tests/conftest.py
Joakim Hellsén 36d55566fc
All checks were successful
Test and build Docker image / docker (push) Successful in 1m48s
Edit sent Discord webhooks if entry values updates
2026-05-09 04:41:50 +02:00

83 lines
3 KiB
Python

from __future__ import annotations
import os
import shutil
import sys
import tempfile
import warnings
from contextlib import suppress
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Protocol
from typing import cast
from bs4 import MarkupResemblesLocatorWarning
if TYPE_CHECKING:
from types import ModuleType
import pytest
class CachedReaderFactory(Protocol):
"""Reader factory with lru_cache controls used by tests."""
def __call__(self) -> None:
"""Create or return the cached reader."""
def cache_clear(self) -> None:
"""Clear the cached reader."""
def pytest_addoption(parser: pytest.Parser) -> None:
"""Register custom command-line options for optional integration tests."""
parser.addoption(
"--run-real-git-backup-tests",
action="store_true",
default=False,
help="Run tests that push git backup state to a real repository.",
)
def pytest_sessionstart(session: pytest.Session) -> None:
"""Isolate persistent app state per xdist worker to avoid cross-worker test interference."""
worker_id: str = os.environ.get("PYTEST_XDIST_WORKER", "gw0")
worker_data_dir: Path = Path(tempfile.gettempdir()) / "discord-rss-bot-tests" / worker_id
# Start each worker from a clean state.
shutil.rmtree(worker_data_dir, ignore_errors=True)
worker_data_dir.mkdir(parents=True, exist_ok=True)
os.environ["DISCORD_RSS_BOT_DATA_DIR"] = str(worker_data_dir)
# Tests call markdownify which may invoke BeautifulSoup on strings that look
# like URLs; that triggers MarkupResemblesLocatorWarning from bs4. Silence
# that warning during tests to avoid noisy output.
warnings.filterwarnings("ignore", category=MarkupResemblesLocatorWarning)
# If modules were imported before this hook (unlikely), force them to use
# the worker-specific location.
settings_module: ModuleType | None = sys.modules.get("discord_rss_bot.settings")
if settings_module is not None:
settings_module.data_dir = str(worker_data_dir)
get_reader_attr = getattr(settings_module, "get_reader", None)
if get_reader_attr is not None and hasattr(get_reader_attr, "cache_clear"):
get_reader = cast("CachedReaderFactory", get_reader_attr)
get_reader.cache_clear()
main_module: ModuleType | None = sys.modules.get("discord_rss_bot.main")
if main_module is not None and settings_module is not None:
with suppress(Exception):
current_reader = getattr(main_module, "reader", None)
if current_reader is not None:
current_reader.close()
get_reader_attr = getattr(settings_module, "get_reader", None)
if callable(get_reader_attr):
get_reader = cast("CachedReaderFactory", get_reader_attr)
get_reader()
def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item]) -> None:
"""Skip real git-repo push tests unless explicitly requested."""
if config.getoption("--run-real-git-backup-tests"):
return