1 Commits
Author SHA1 Message Date
xavierk 512df2ae83 fix(store): default store_path when config omits it (issue #53)
Release / release (push) Successful in 59s
Fresh installs shipped a config template with no store_path key while
collector.py demanded one via get_store_path() — every first collect
crashed with KeyError 'store_path'. Resolve to the packaged default
(/var/lib/fenris/observations.db) when absent, document the key in the
template, and cover the fresh-install path with regression tests.
Bump to 0.3.2.
2026-09-10 09:45:02 +05:30
4 changed files with 74 additions and 3 deletions
+5
View File
@@ -8,4 +8,9 @@
#
# device = /dev/disk/by-id/nvme-Samsung_SSD_980_PRO_500GB_S5PANS0T123456
#
# The observation store path is optional and defaults to
# /var/lib/fenris/observations.db when unset:
#
# store_path = /var/lib/fenris/observations.db
#
# See https://git.bongbetic.com/xavierk/Fenris for documentation.
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "fenris"
version = "0.3.1"
version = "0.3.2"
description = "NVMe wear monitor with persistent TUI"
requires-python = ">=3.9"
dependencies = [
+12 -2
View File
@@ -15,9 +15,19 @@ from typing import Optional
SCHEMA_VERSION = 1
# Packaged default placement (spec §8.3). The config may override it, but a
# fresh install that sets only the device selector must collect cleanly.
DEFAULT_STORE_PATH = Path("/var/lib/fenris/observations.db")
def get_store_path(config: dict) -> Path:
"""Get the store path from config."""
return Path(config["store_path"])
"""Get the store path from config.
Falls back to the packaged default when the config does not pin one,
so a fresh install whose config holds only the device selector works
instead of crashing with KeyError 'store_path' (issue #53).
"""
return Path(config.get("store_path", DEFAULT_STORE_PATH))
def init_store(store_path: Path) -> sqlite3.Connection:
+56
View File
@@ -0,0 +1,56 @@
"""Store path resolution from config — regression coverage for issue #53.
A fresh install ships a placeholder-commented config whose only required
key is the device selector. The collector must not crash with
KeyError 'store_path' when the key is absent.
"""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
from fenris.store import DEFAULT_STORE_PATH, get_store_path
REPO_ROOT = Path(__file__).resolve().parent.parent
TEMPLATE = REPO_ROOT / "packaging" / "fenris.conf"
def _parse_like_load_config(text: str) -> dict:
"""Mirror collect.load_config()'s key=value parsing rules."""
config = {}
for line in text.splitlines():
line = line.strip()
if not line or line.startswith("#"):
continue
if "=" in line:
key, value = line.split("=", 1)
config[key.strip()] = value.strip()
return config
def test_missing_store_path_falls_back_to_default():
"""Config with only the device selector resolves to the packaged default."""
assert get_store_path({"device": "/dev/nvme0n1"}) == DEFAULT_STORE_PATH
def test_explicit_store_path_wins():
"""An explicit store_path override is honored."""
assert get_store_path({"store_path": "/tmp/other.db"}) == Path("/tmp/other.db")
def test_packaged_template_yields_collectable_config():
"""The packaged template, once a device is set, must be collector-ready.
Reproduces the fresh-install path: parse packaging/fenris.conf the way
collect.load_config() does, add the device selector, then resolve the
store. Issue #53 made this raise KeyError.
"""
config = _parse_like_load_config(TEMPLATE.read_text())
config["device"] = "/dev/nvme0n1"
assert get_store_path(config) == DEFAULT_STORE_PATH
def test_template_documents_store_path():
"""The template must mention store_path so admins know it is overridable."""
assert "store_path" in TEMPLATE.read_text()