Files
dropbox_helper/tests/test_config.py
T
jared c7705b9599
CI / Tests (macOS) (push) Has been cancelled
CI / Tests (Windows) (push) Has been cancelled
CI / Tests (Linux, Python 3.11) (push) Has been cancelled
CI / Tests (Linux, Python 3.12) (push) Has been cancelled
CI / Tests (Linux, Python 3.9) (push) Has been cancelled
fix: handle missing keyring backend in CI
The keyring package imports successfully on headless Linux but uses a
fail.Keyring backend that raises NoKeyringError on any operation. Detect
this case in _get_keyring() and fall back to the file-based token store.
2026-04-20 14:34:17 -04:00

115 lines
3.4 KiB
Python

"""Tests for tagsync.config: Settings persistence + token storage."""
from __future__ import annotations
import importlib
import json
import pytest
@pytest.fixture
def config_module():
from tagsync import config
return importlib.reload(config)
# --- Settings ---------------------------------------------------------------
def test_settings_defaults(config_module):
s = config_module.Settings()
assert s.local_root == ""
assert s.platform == ""
assert s.skip_online_only is True
assert s.write_sidecars is False
assert s.schedule_installed is False
assert s.schedule_interval_minutes == 60
def test_settings_roundtrip(config_module, tmp_path):
path = tmp_path / "cfg.json"
original = config_module.Settings(
local_root="/home/u/Dropbox",
platform="macos",
skip_online_only=False,
schedule_installed=True,
schedule_interval_minutes=30,
)
original.save(path)
loaded = config_module.Settings.load(path)
assert loaded == original
def test_settings_load_missing_file_returns_defaults(config_module, tmp_path):
loaded = config_module.Settings.load(tmp_path / "nope.json")
assert loaded == config_module.Settings()
def test_settings_load_ignores_unknown_keys(config_module, tmp_path):
"""Older configs should load even if a new field was removed."""
path = tmp_path / "cfg.json"
path.write_text(json.dumps({
"local_root": "/x",
"platform": "macos",
"future_field_we_dont_know_about": 42,
}))
loaded = config_module.Settings.load(path)
assert loaded.local_root == "/x"
assert loaded.platform == "macos"
# --- Token storage (fallback file path) -------------------------------------
def test_token_fallback_roundtrip(config_module, monkeypatch):
"""Force the non-keyring fallback path and verify round-trip."""
monkeypatch.setattr(config_module, "_get_keyring", lambda: None)
assert config_module.load_token() is None
location = config_module.save_token("sl.test-token-123")
assert "plaintext" in location
assert config_module.load_token() == "sl.test-token-123"
config_module.clear_token()
assert config_module.load_token() is None
def test_token_fallback_file_permissions(config_module, monkeypatch):
"""The fallback token file should be mode 0600 where supported."""
import os
import stat
monkeypatch.setattr(config_module, "_get_keyring", lambda: None)
config_module.save_token("sl.perm-test")
mode = os.stat(config_module.TOKEN_FALLBACK_FILE).st_mode
# Skip on Windows where POSIX modes aren't enforced the same way.
if os.name == "posix":
assert stat.S_IMODE(mode) == 0o600
@pytest.mark.needs_keyring
def test_token_keyring_roundtrip(config_module):
"""If keyring is installed, verify we actually use it."""
pytest.importorskip("keyring")
if config_module._get_keyring() is None:
pytest.skip("keyring not usable")
import keyring
# Use the in-memory fallback backend to avoid touching real Keychain.
from keyring.backends import fail as _fail # noqa: F401 (ensure package)
try:
import keyring.backends.null
keyring.set_keyring(keyring.backends.null.Keyring())
except Exception:
pytest.skip("no safe keyring backend available for tests")
# Null keyring swallows set/get — just exercise code paths.
config_module.save_token("sl.kr-test")
config_module.clear_token()