mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-02 19:02:31 +00:00
fix: one source for the disk type and a config volume for SearXNG
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
"""Every view of a disk takes its rotation and type from disk_identity."""
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import tempfile
|
||||
import types
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "AppImage/scripts"))
|
||||
import disk_identity
|
||||
import audit_inventory
|
||||
|
||||
|
||||
class DiskMediaTypeTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
folder = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(folder.cleanup)
|
||||
self.root = Path(folder.name)
|
||||
for name, flag in (("sda", "1"), ("sdb", "0"), ("nvme0n1", "0")):
|
||||
(self.root / name / "queue").mkdir(parents=True)
|
||||
(self.root / name / "queue/rotational").write_text(flag + "\n")
|
||||
sys_block = patch.object(disk_identity, "_SYS_BLOCK", str(self.root))
|
||||
sys_block.start()
|
||||
self.addCleanup(sys_block.stop)
|
||||
|
||||
def test_the_kernel_flag_answers_when_smartctl_did_not(self):
|
||||
self.assertEqual(disk_identity.rotation_rate("sda"), -1)
|
||||
self.assertEqual(disk_identity.rotation_rate("sdb"), 0)
|
||||
self.assertEqual(disk_identity.rotation_rate("sdz"), 0)
|
||||
|
||||
def test_what_smartctl_reported_wins(self):
|
||||
self.assertEqual(disk_identity.rotation_rate("sda", 0), 0)
|
||||
self.assertEqual(disk_identity.rotation_rate("sdb", 5400), 5400)
|
||||
self.assertEqual(disk_identity.rotation_rate("sda", None), -1)
|
||||
|
||||
def test_media_type(self):
|
||||
self.assertEqual(disk_identity.media_type("sda", -1), "HDD")
|
||||
self.assertEqual(disk_identity.media_type("sda", 7200), "HDD")
|
||||
self.assertEqual(disk_identity.media_type("sdb", 0), "SSD")
|
||||
self.assertEqual(disk_identity.media_type("nvme0n1", 0), "NVMe")
|
||||
|
||||
def test_the_inventory_agrees_with_the_monitor(self):
|
||||
rows = ('NAME="sda" MODEL="WDC WD7500BPVT" SERIAL="WX1" SIZE="750156374016" ROTA="1" TRAN="usb" TYPE="disk"\n'
|
||||
'NAME="sdb" MODEL="Samsung SSD" SERIAL="S1" SIZE="500107862016" ROTA="0" TRAN="sata" TYPE="disk"\n')
|
||||
ctx = types.SimpleNamespace(run=lambda *a, **k: (0, rows),
|
||||
monitor_snapshot={"smart": {"/dev/sda": [0, {"rotation_rate": 0}]}})
|
||||
with patch.object(audit_inventory, "_disk_observations", return_value={}):
|
||||
disks = {d["name"]: d["rotational"] for d in audit_inventory._physical_disks(ctx)}
|
||||
# The USB bridge marks sda rotational; smartctl, through the Monitor, says solid state.
|
||||
self.assertEqual(disks, {"sda": False, "sdb": False})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -209,10 +209,16 @@ class QuietDiskIdentityTests(unittest.TestCase):
|
||||
self.read = Mock(return_value={"model": "WDC WD40EFRX-68N32N0", "serial": "WD-WCC7K4FV37J0",
|
||||
"rotation_rate": 5400, "health": "healthy", "temperature": 31})
|
||||
self.cache = {}
|
||||
self.backoff = {}
|
||||
import disk_identity
|
||||
sys_block = patch.object(disk_identity, "_SYS_BLOCK", str(root / "sys/block"))
|
||||
sys_block.start()
|
||||
self.addCleanup(sys_block.stop)
|
||||
namespace = {"Path": lambda path: root / path.lstrip("/"), "time": __import__("time"),
|
||||
"disk_identity": disk_identity,
|
||||
"_smart_result_cache": self.cache, "_SMART_RESULT_TTL": 30, "_hdd_in_standby": self.standby,
|
||||
"_get_smart_data_uncached": self.read, "_smart_data_useful": lambda data: data.get("model") != "Unknown",
|
||||
"_smart_fail_backoff": {}, "_smart_fail_counts": {}, "_smart_probe_cache": {},
|
||||
"_smart_fail_backoff": self.backoff, "_smart_fail_counts": {}, "_smart_probe_cache": {},
|
||||
"_SMART_FAIL_THRESHOLD": 3, "_SMART_FAIL_BACKOFF_SEC": 3600}
|
||||
tree = ast.parse((SCRIPTS / "flask_server.py").read_text())
|
||||
nodes = [n for n in tree.body if isinstance(n, ast.FunctionDef)
|
||||
@@ -240,6 +246,13 @@ class QuietDiskIdentityTests(unittest.TestCase):
|
||||
self.read.assert_not_called()
|
||||
self.assertEqual((data["model"], data["rotation_rate"], data["excluded"]), ("WDC WD40EFRX-68N32N0", -1, True))
|
||||
|
||||
def test_a_disk_smartctl_keeps_failing_on_keeps_its_identity(self):
|
||||
self.backoff["sdb"] = __import__("time").time() + 3600
|
||||
data = self.get("sdb")
|
||||
self.read.assert_not_called()
|
||||
self.assertEqual((data["model"], data["serial"], data["rotation_rate"]),
|
||||
("WDC WD40EFRX-68N32N0", "WD-WCC7K4FV37J0", -1))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -55,12 +55,15 @@ console.log('PASS: saved-data badge guards and actual provider fallback/translat
|
||||
const report = source.statements.find(n => ts.isFunctionDeclaration(n) && n.name?.text === 'openSmartReport');
|
||||
assert.ok(report);
|
||||
let reportHtml;
|
||||
const diskTypeModule = {};
|
||||
new Function('exports', compile(read('AppImage/lib/disk-type.ts')))(diskTypeModule);
|
||||
const openReport = new Function('window', 'Blob', 'URL', 'setTimeout', 'getDiskTempThresholdsSync', 'getNvmeSmartAttributeKey',
|
||||
'resolveDiskType',
|
||||
compile('const APP_VERSION = "fixture";\n' + emit(report, source)) + '\nreturn openSmartReport;')(
|
||||
{location: {origin: 'http://fixture.invalid'}, open() {}},
|
||||
class { constructor(parts) { reportHtml = parts.join(''); } },
|
||||
{createObjectURL() { return 'blob:fixture'; }, revokeObjectURL() {}}, () => {},
|
||||
() => ({warning: 55, critical: 65}), () => undefined);
|
||||
() => ({warning: 55, critical: 65}), () => undefined, diskTypeModule.getDiskType);
|
||||
const expectedReport = {
|
||||
passedAssessment: 'The supplied SMART status is PASSED. This status alone does not establish that every attribute is within range or that the disk is free of faults. Power-on time shown: {uptime}. Temperature shown: {temperature}. {sectors}',
|
||||
noReallocatedSectorsReported: 'The supplied reallocated-sector value is zero or unavailable; this does not establish that there are no bad sectors.',
|
||||
@@ -107,5 +110,15 @@ translated.recommendations = {passedTitle: 'TRANSLATED_REC_TITLE', passedText: '
|
||||
const localized = renderReport({}, 'passed', 'synthetic', {...catalogs, synthetic: {storage: {smartReport: translated}}});
|
||||
for (const [, value] of leaves(translated)) assert.ok(localized.includes(value.split(' {')[0]), value);
|
||||
assert.ok(renderReport({name: 'nvme0n1'}, 'passed', 'en', catalogs, {nvme_raw: {critical_warning: 0, media_errors: 7}}).includes(expectedReport.passedMeaning));
|
||||
// One classifier for the report and the Storage page: a disk the kernel marks
|
||||
// rotational without an RPM is an HDD, and a real model wins over "Unknown".
|
||||
const typeCard = html => html.match(/labels\.type[^]*?card-value[^>]*>([^<]*)</)?.[1] ?? html.match(/>Type<\/div>\s*<div class="card-value"[^>]*>([^<]*)</)?.[1];
|
||||
assert.equal(typeCard(renderReport({rotation_rate: -1})), 'HDD');
|
||||
assert.equal(typeCard(renderReport({rotation_rate: 7200})), 'HDD 7200 RPM');
|
||||
assert.equal(typeCard(renderReport({rotation_rate: 0})), 'SSD');
|
||||
assert.ok(!renderReport({rotation_rate: -1}).includes('-1 RPM'));
|
||||
assert.equal(typeCard(renderReport({rotation_rate: -1, connection_type: 'sas'})), 'SAS HDD');
|
||||
const unknownModel = renderReport({model: 'Unknown', serial: 'Unknown'}, 'passed', 'en', catalogs, {model: 'WDC WD7500BPVT', serial: 'WX11A1234'});
|
||||
assert.ok(unknownModel.includes('WDC WD7500BPVT') && unknownModel.includes('WX11A1234'));
|
||||
if (process.env.STORAGE_REPORT_HTML) fs.writeFileSync(process.env.STORAGE_REPORT_HTML, renderReport());
|
||||
console.log('PASS: actual printable report, passed/failed/unknown/warning, missing/zero/nonzero sectors, NVMe errors and provider fallback');
|
||||
|
||||
Reference in New Issue
Block a user