mirror of
https://github.com/RichieCahill/dotfiles.git
synced 2026-04-17 04:58:19 -04:00
Add comprehensive test suite achieving 99% code coverage
Added 35 test files with 502 tests covering all Python modules including API routes, ORM models, splendor game logic/TUI, heater controller, weather service, NixOS installer, ZFS dataset management, and utilities. Coverage improved from 11% to 99% (2540/2564 statements covered). https://claude.ai/code/session_01SVzgLDUS1Cdc4eh1ijETTh
This commit is contained in:
361
tests/test_zfs_dataset.py
Normal file
361
tests/test_zfs_dataset.py
Normal file
@@ -0,0 +1,361 @@
|
||||
"""Tests for python/zfs/dataset.py covering missing lines."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from python.zfs.dataset import Dataset, Snapshot, _zfs_list
|
||||
|
||||
DATASET = "python.zfs.dataset"
|
||||
|
||||
SAMPLE_SNAPSHOT_DATA = {
|
||||
"createtxg": "123",
|
||||
"properties": {
|
||||
"creation": {"value": "1620000000"},
|
||||
"defer_destroy": {"value": "off"},
|
||||
"guid": {"value": "456"},
|
||||
"objsetid": {"value": "789"},
|
||||
"referenced": {"value": "1024"},
|
||||
"used": {"value": "512"},
|
||||
"userrefs": {"value": "0"},
|
||||
"version": {"value": "1"},
|
||||
"written": {"value": "2048"},
|
||||
},
|
||||
"name": "pool/dataset@snap1",
|
||||
}
|
||||
|
||||
SAMPLE_DATASET_DATA = {
|
||||
"output_version": {"vers_major": 0, "vers_minor": 1, "command": "zfs list"},
|
||||
"datasets": {
|
||||
"pool/dataset": {
|
||||
"properties": {
|
||||
"aclinherit": {"value": "restricted"},
|
||||
"aclmode": {"value": "discard"},
|
||||
"acltype": {"value": "off"},
|
||||
"available": {"value": "1000000"},
|
||||
"canmount": {"value": "on"},
|
||||
"checksum": {"value": "on"},
|
||||
"clones": {"value": ""},
|
||||
"compression": {"value": "lz4"},
|
||||
"copies": {"value": "1"},
|
||||
"createtxg": {"value": "1234"},
|
||||
"creation": {"value": "1620000000"},
|
||||
"dedup": {"value": "off"},
|
||||
"devices": {"value": "on"},
|
||||
"encryption": {"value": "off"},
|
||||
"exec": {"value": "on"},
|
||||
"filesystem_limit": {"value": "none"},
|
||||
"guid": {"value": "5678"},
|
||||
"keystatus": {"value": "none"},
|
||||
"logbias": {"value": "latency"},
|
||||
"mlslabel": {"value": "none"},
|
||||
"mounted": {"value": "yes"},
|
||||
"mountpoint": {"value": "/pool/dataset"},
|
||||
"quota": {"value": "0"},
|
||||
"readonly": {"value": "off"},
|
||||
"recordsize": {"value": "131072"},
|
||||
"redundant_metadata": {"value": "all"},
|
||||
"referenced": {"value": "512000"},
|
||||
"refquota": {"value": "0"},
|
||||
"refreservation": {"value": "0"},
|
||||
"reservation": {"value": "0"},
|
||||
"setuid": {"value": "on"},
|
||||
"sharenfs": {"value": "off"},
|
||||
"snapdir": {"value": "hidden"},
|
||||
"snapshot_limit": {"value": "none"},
|
||||
"sync": {"value": "standard"},
|
||||
"used": {"value": "1024000"},
|
||||
"usedbychildren": {"value": "512000"},
|
||||
"usedbydataset": {"value": "256000"},
|
||||
"usedbysnapshots": {"value": "256000"},
|
||||
"version": {"value": "5"},
|
||||
"volmode": {"value": "default"},
|
||||
"volsize": {"value": "none"},
|
||||
"vscan": {"value": "off"},
|
||||
"written": {"value": "4096"},
|
||||
"xattr": {"value": "on"},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _make_dataset() -> Dataset:
|
||||
"""Create a Dataset instance with mocked _zfs_list."""
|
||||
with patch(f"{DATASET}._zfs_list", return_value=SAMPLE_DATASET_DATA):
|
||||
return Dataset("pool/dataset")
|
||||
|
||||
|
||||
# --- _zfs_list version check error (line 29) ---
|
||||
|
||||
|
||||
def test_zfs_list_returns_data_on_valid_version() -> None:
|
||||
"""Test _zfs_list returns parsed data when version is correct."""
|
||||
valid_data = {
|
||||
"output_version": {"vers_major": 0, "vers_minor": 1, "command": "zfs list"},
|
||||
"datasets": {},
|
||||
}
|
||||
with patch(f"{DATASET}.bash_wrapper", return_value=(json.dumps(valid_data), 0)):
|
||||
result = _zfs_list("zfs list pool -pHj -o all")
|
||||
assert result == valid_data
|
||||
|
||||
|
||||
def test_zfs_list_raises_on_wrong_vers_minor() -> None:
|
||||
"""Test _zfs_list raises RuntimeError when vers_minor is wrong."""
|
||||
bad_data = {
|
||||
"output_version": {"vers_major": 0, "vers_minor": 2, "command": "zfs list"},
|
||||
}
|
||||
with (
|
||||
patch(f"{DATASET}.bash_wrapper", return_value=(json.dumps(bad_data), 0)),
|
||||
pytest.raises(RuntimeError, match="Datasets are not in the correct format"),
|
||||
):
|
||||
_zfs_list("zfs list pool -pHj -o all")
|
||||
|
||||
|
||||
def test_zfs_list_raises_on_wrong_command() -> None:
|
||||
"""Test _zfs_list raises RuntimeError when command field is wrong."""
|
||||
bad_data = {
|
||||
"output_version": {"vers_major": 0, "vers_minor": 1, "command": "zpool list"},
|
||||
}
|
||||
with (
|
||||
patch(f"{DATASET}.bash_wrapper", return_value=(json.dumps(bad_data), 0)),
|
||||
pytest.raises(RuntimeError, match="Datasets are not in the correct format"),
|
||||
):
|
||||
_zfs_list("zfs list pool -pHj -o all")
|
||||
|
||||
|
||||
# --- Snapshot.__repr__() (line 52) ---
|
||||
|
||||
|
||||
def test_snapshot_repr() -> None:
|
||||
"""Test Snapshot __repr__ returns correct format."""
|
||||
snapshot = Snapshot(SAMPLE_SNAPSHOT_DATA)
|
||||
result = repr(snapshot)
|
||||
assert result == "name=snap1 used=512 refer=1024"
|
||||
|
||||
|
||||
def test_snapshot_repr_different_values() -> None:
|
||||
"""Test Snapshot __repr__ with different values."""
|
||||
data = {
|
||||
**SAMPLE_SNAPSHOT_DATA,
|
||||
"name": "pool/dataset@daily-2024-01-01",
|
||||
"properties": {
|
||||
**SAMPLE_SNAPSHOT_DATA["properties"],
|
||||
"used": {"value": "999"},
|
||||
"referenced": {"value": "5555"},
|
||||
},
|
||||
}
|
||||
snapshot = Snapshot(data)
|
||||
assert "daily-2024-01-01" in repr(snapshot)
|
||||
assert "999" in repr(snapshot)
|
||||
assert "5555" in repr(snapshot)
|
||||
|
||||
|
||||
# --- Dataset.get_snapshots() (lines 113-115) ---
|
||||
|
||||
|
||||
def test_dataset_get_snapshots() -> None:
|
||||
"""Test Dataset.get_snapshots returns list of Snapshot objects."""
|
||||
dataset = _make_dataset()
|
||||
|
||||
snapshot_list_data = {
|
||||
"output_version": {"vers_major": 0, "vers_minor": 1, "command": "zfs list"},
|
||||
"datasets": {
|
||||
"pool/dataset@snap1": SAMPLE_SNAPSHOT_DATA,
|
||||
"pool/dataset@snap2": {
|
||||
**SAMPLE_SNAPSHOT_DATA,
|
||||
"name": "pool/dataset@snap2",
|
||||
},
|
||||
},
|
||||
}
|
||||
with patch(f"{DATASET}._zfs_list", return_value=snapshot_list_data):
|
||||
snapshots = dataset.get_snapshots()
|
||||
|
||||
assert snapshots is not None
|
||||
assert len(snapshots) == 2
|
||||
assert all(isinstance(s, Snapshot) for s in snapshots)
|
||||
|
||||
|
||||
def test_dataset_get_snapshots_empty() -> None:
|
||||
"""Test Dataset.get_snapshots returns empty list when no snapshots."""
|
||||
dataset = _make_dataset()
|
||||
|
||||
snapshot_list_data = {
|
||||
"output_version": {"vers_major": 0, "vers_minor": 1, "command": "zfs list"},
|
||||
"datasets": {},
|
||||
}
|
||||
with patch(f"{DATASET}._zfs_list", return_value=snapshot_list_data):
|
||||
snapshots = dataset.get_snapshots()
|
||||
|
||||
assert snapshots == []
|
||||
|
||||
|
||||
# --- Dataset.create_snapshot() (lines 123-133) ---
|
||||
|
||||
|
||||
def test_dataset_create_snapshot_success() -> None:
|
||||
"""Test create_snapshot returns success message when return code is 0."""
|
||||
dataset = _make_dataset()
|
||||
|
||||
with patch(f"{DATASET}.bash_wrapper", return_value=("", 0)):
|
||||
result = dataset.create_snapshot("my-snap")
|
||||
|
||||
assert result == "snapshot created"
|
||||
|
||||
|
||||
def test_dataset_create_snapshot_already_exists() -> None:
|
||||
"""Test create_snapshot returns message when snapshot already exists."""
|
||||
dataset = _make_dataset()
|
||||
|
||||
snapshot_list_data = {
|
||||
"output_version": {"vers_major": 0, "vers_minor": 1, "command": "zfs list"},
|
||||
"datasets": {
|
||||
"pool/dataset@my-snap": SAMPLE_SNAPSHOT_DATA,
|
||||
},
|
||||
}
|
||||
|
||||
with (
|
||||
patch(f"{DATASET}.bash_wrapper", return_value=("dataset already exists", 1)),
|
||||
patch(f"{DATASET}._zfs_list", return_value=snapshot_list_data),
|
||||
):
|
||||
# The snapshot data has name "pool/dataset@snap1" which extracts to "snap1"
|
||||
# We need the snapshot name to match, so use "snap1"
|
||||
result = dataset.create_snapshot("snap1")
|
||||
|
||||
assert "already exists" in result
|
||||
|
||||
|
||||
def test_dataset_create_snapshot_failure() -> None:
|
||||
"""Test create_snapshot returns failure message on unknown error."""
|
||||
dataset = _make_dataset()
|
||||
|
||||
snapshot_list_data = {
|
||||
"output_version": {"vers_major": 0, "vers_minor": 1, "command": "zfs list"},
|
||||
"datasets": {},
|
||||
}
|
||||
|
||||
with (
|
||||
patch(f"{DATASET}.bash_wrapper", return_value=("some error", 1)),
|
||||
patch(f"{DATASET}._zfs_list", return_value=snapshot_list_data),
|
||||
):
|
||||
result = dataset.create_snapshot("new-snap")
|
||||
|
||||
assert "Failed to create snapshot" in result
|
||||
|
||||
|
||||
def test_dataset_create_snapshot_failure_no_snapshots() -> None:
|
||||
"""Test create_snapshot failure when get_snapshots returns empty list."""
|
||||
dataset = _make_dataset()
|
||||
|
||||
# get_snapshots returns empty list (falsy), so the if branch is skipped
|
||||
snapshot_list_data = {
|
||||
"output_version": {"vers_major": 0, "vers_minor": 1, "command": "zfs list"},
|
||||
"datasets": {},
|
||||
}
|
||||
|
||||
with (
|
||||
patch(f"{DATASET}.bash_wrapper", return_value=("error", 1)),
|
||||
patch(f"{DATASET}._zfs_list", return_value=snapshot_list_data),
|
||||
):
|
||||
result = dataset.create_snapshot("nonexistent")
|
||||
|
||||
assert "Failed to create snapshot" in result
|
||||
|
||||
|
||||
# --- Dataset.delete_snapshot() (lines 141-148) ---
|
||||
|
||||
|
||||
def test_dataset_delete_snapshot_success() -> None:
|
||||
"""Test delete_snapshot returns None on success."""
|
||||
dataset = _make_dataset()
|
||||
|
||||
with patch(f"{DATASET}.bash_wrapper", return_value=("", 0)):
|
||||
result = dataset.delete_snapshot("my-snap")
|
||||
|
||||
assert result is None
|
||||
|
||||
|
||||
def test_dataset_delete_snapshot_dependent_clones() -> None:
|
||||
"""Test delete_snapshot returns message when snapshot has dependent clones."""
|
||||
dataset = _make_dataset()
|
||||
|
||||
error_msg = "cannot destroy 'pool/dataset@my-snap': snapshot has dependent clones"
|
||||
with patch(f"{DATASET}.bash_wrapper", return_value=(error_msg, 1)):
|
||||
result = dataset.delete_snapshot("my-snap")
|
||||
|
||||
assert result == "snapshot has dependent clones"
|
||||
|
||||
|
||||
def test_dataset_delete_snapshot_other_failure() -> None:
|
||||
"""Test delete_snapshot raises RuntimeError on other failures."""
|
||||
dataset = _make_dataset()
|
||||
|
||||
with (
|
||||
patch(f"{DATASET}.bash_wrapper", return_value=("some other error", 1)),
|
||||
pytest.raises(RuntimeError, match="Failed to delete snapshot"),
|
||||
):
|
||||
dataset.delete_snapshot("my-snap")
|
||||
|
||||
|
||||
# --- Dataset.__repr__() (line 152) ---
|
||||
|
||||
|
||||
def test_dataset_repr() -> None:
|
||||
"""Test Dataset __repr__ includes all attributes."""
|
||||
dataset = _make_dataset()
|
||||
result = repr(dataset)
|
||||
|
||||
expected_attrs = [
|
||||
"aclinherit",
|
||||
"aclmode",
|
||||
"acltype",
|
||||
"available",
|
||||
"canmount",
|
||||
"checksum",
|
||||
"clones",
|
||||
"compression",
|
||||
"copies",
|
||||
"createtxg",
|
||||
"creation",
|
||||
"dedup",
|
||||
"devices",
|
||||
"encryption",
|
||||
"exec",
|
||||
"filesystem_limit",
|
||||
"guid",
|
||||
"keystatus",
|
||||
"logbias",
|
||||
"mlslabel",
|
||||
"mounted",
|
||||
"mountpoint",
|
||||
"name",
|
||||
"quota",
|
||||
"readonly",
|
||||
"recordsize",
|
||||
"redundant_metadata",
|
||||
"referenced",
|
||||
"refquota",
|
||||
"refreservation",
|
||||
"reservation",
|
||||
"setuid",
|
||||
"sharenfs",
|
||||
"snapdir",
|
||||
"snapshot_limit",
|
||||
"sync",
|
||||
"used",
|
||||
"usedbychildren",
|
||||
"usedbydataset",
|
||||
"usedbysnapshots",
|
||||
"version",
|
||||
"volmode",
|
||||
"volsize",
|
||||
"vscan",
|
||||
"written",
|
||||
"xattr",
|
||||
]
|
||||
|
||||
for attr in expected_attrs:
|
||||
assert f"self.{attr}=" in result, f"Missing {attr} in repr"
|
||||
Reference in New Issue
Block a user