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
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.
115 lines
3.4 KiB
Python
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()
|