154 lines
5.7 KiB
Python
154 lines
5.7 KiB
Python
from pathlib import Path
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
from app.main import create_app
|
|
from app.system.performance import PerformanceModeError, PerformanceModeManager
|
|
|
|
|
|
def make_policy(root: Path, name: str, governor: str = "schedutil") -> Path:
|
|
policy = root / name
|
|
policy.mkdir(parents=True)
|
|
(policy / "scaling_governor").write_text(f"{governor}\n", encoding="ascii")
|
|
(policy / "scaling_available_governors").write_text(
|
|
"conservative ondemand userspace powersave performance schedutil\n",
|
|
encoding="ascii",
|
|
)
|
|
return policy
|
|
|
|
|
|
def read_governor(policy: Path) -> str:
|
|
return (policy / "scaling_governor").read_text(encoding="ascii").strip()
|
|
|
|
|
|
def test_performance_mode_applies_all_policies_and_restores_baseline(tmp_path):
|
|
sysfs = tmp_path / "sysfs"
|
|
policy0 = make_policy(sysfs, "policy0", "schedutil")
|
|
policy4 = make_policy(sysfs, "policy4", "powersave")
|
|
manager = PerformanceModeManager(tmp_path / "run", sysfs_root=sysfs)
|
|
saved: list[bool] = []
|
|
|
|
manager.transact(True, saved.append)
|
|
|
|
assert saved == [True]
|
|
assert read_governor(policy0) == "performance"
|
|
assert read_governor(policy4) == "performance"
|
|
assert manager.status(True) == {
|
|
"requested": True,
|
|
"available": True,
|
|
"effective": True,
|
|
"current_governors": {"policy0": "performance", "policy4": "performance"},
|
|
"restore_governors": {"policy0": "schedutil", "policy4": "powersave"},
|
|
"last_error": None,
|
|
}
|
|
|
|
manager.transact(False, saved.append)
|
|
|
|
assert saved == [True, False]
|
|
assert read_governor(policy0) == "schedutil"
|
|
assert read_governor(policy4) == "powersave"
|
|
|
|
|
|
def test_performance_mode_rolls_back_all_policies_when_write_fails(tmp_path, monkeypatch):
|
|
sysfs = tmp_path / "sysfs"
|
|
policy0 = make_policy(sysfs, "policy0", "schedutil")
|
|
policy4 = make_policy(sysfs, "policy4", "powersave")
|
|
manager = PerformanceModeManager(tmp_path / "run", sysfs_root=sysfs)
|
|
original_write = manager._write_text
|
|
failed = False
|
|
|
|
def fail_policy4(path: Path, value: str) -> None:
|
|
nonlocal failed
|
|
if path.parent.name == "policy4" and value == "performance" and not failed:
|
|
failed = True
|
|
raise OSError("injected write failure")
|
|
original_write(path, value)
|
|
|
|
monkeypatch.setattr(manager, "_write_text", fail_policy4)
|
|
|
|
with pytest.raises(PerformanceModeError, match="injected write failure"):
|
|
manager.transact(True, lambda _enabled: None)
|
|
|
|
assert read_governor(policy0) == "schedutil"
|
|
assert read_governor(policy4) == "powersave"
|
|
assert manager.status(False)["effective"] is False
|
|
|
|
|
|
def test_performance_mode_rolls_back_governors_when_persistence_fails(tmp_path):
|
|
sysfs = tmp_path / "sysfs"
|
|
policy0 = make_policy(sysfs, "policy0", "schedutil")
|
|
manager = PerformanceModeManager(tmp_path / "run", sysfs_root=sysfs)
|
|
|
|
def fail_persist(_enabled: bool) -> None:
|
|
raise OSError("injected persistence failure")
|
|
|
|
with pytest.raises(PerformanceModeError, match="transaction failed"):
|
|
manager.transact(True, fail_persist)
|
|
|
|
assert read_governor(policy0) == "schedutil"
|
|
assert manager.status(False)["last_error"] == "injected persistence failure"
|
|
|
|
|
|
def test_preserved_record_prevents_performance_from_becoming_restart_baseline(tmp_path):
|
|
sysfs = tmp_path / "sysfs"
|
|
policy0 = make_policy(sysfs, "policy0", "schedutil")
|
|
runtime = tmp_path / "run"
|
|
first = PerformanceModeManager(runtime, sysfs_root=sysfs)
|
|
first.transact(True, lambda _enabled: None)
|
|
|
|
restarted = PerformanceModeManager(runtime, sysfs_root=sysfs)
|
|
|
|
assert restarted.status(True)["restore_governors"] == {"policy0": "schedutil"}
|
|
restarted.restore(remove_record=True)
|
|
assert read_governor(policy0) == "schedutil"
|
|
assert not restarted.record_path.exists()
|
|
|
|
|
|
def test_unavailable_cpufreq_is_reported_without_fake_success(tmp_path):
|
|
manager = PerformanceModeManager(tmp_path / "run", sysfs_root=tmp_path / "missing")
|
|
|
|
assert manager.status(False) == {
|
|
"requested": False,
|
|
"available": False,
|
|
"effective": False,
|
|
"current_governors": {},
|
|
"restore_governors": {},
|
|
"last_error": None,
|
|
}
|
|
with pytest.raises(PerformanceModeError, match="unavailable"):
|
|
manager.transact(True, lambda _enabled: None)
|
|
|
|
|
|
def test_config_api_performance_mode_is_transactional_with_fake_sysfs(tmp_path):
|
|
sysfs = tmp_path / "sysfs"
|
|
policy0 = make_policy(sysfs, "policy0", "schedutil")
|
|
|
|
def factory(runtime_root: Path) -> PerformanceModeManager:
|
|
return PerformanceModeManager(runtime_root, sysfs_root=sysfs)
|
|
|
|
with TestClient(
|
|
create_app(
|
|
project_root=tmp_path / "project",
|
|
driver_kind="mock",
|
|
performance_manager_factory=factory,
|
|
)
|
|
) as client:
|
|
initial = client.get("/api/status").json()["system"]["performance_mode"]
|
|
assert initial["requested"] is False
|
|
assert initial["available"] is True
|
|
assert read_governor(policy0) == "schedutil"
|
|
|
|
enabled = client.put("/api/config", json={"performance_mode_enabled": True})
|
|
assert enabled.status_code == 200
|
|
assert enabled.json()["performance_mode_enabled"] is True
|
|
assert read_governor(policy0) == "performance"
|
|
assert client.get("/api/status").json()["system"]["performance_mode"]["effective"] is True
|
|
|
|
disabled = client.put("/api/config", json={"performance_mode_enabled": False})
|
|
assert disabled.status_code == 200
|
|
assert disabled.json()["performance_mode_enabled"] is False
|
|
assert read_governor(policy0) == "schedutil"
|
|
|
|
assert read_governor(policy0) == "schedutil"
|