mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-25 21:20:00 +00:00
160701bb42
The Workloads table put a second line under memory and disk cells on
every stopped guest ("N/A / Unavailable", "- / Unavailable"), on every
agentless VM's disk, and "May include cache" under every agentless VM's
memory bar, even at 20%. None of them said why or what to do, and they
broke the row rhythm.
Memory that cannot be read now renders the same dash as an unreadable
disk, with its reason in the cell title, the sparkline's hover title
and assistive text. Disk shows a visible label only for a retained
reading (Last known) or a read the user can fix (No permission, Agent
error). The cache caption appears only when the guest's own memory is
at its warning or critical threshold, the figure that colours the bar
in host-share mode too, which is the case #2762 and #2639 were about;
below that the caveat stays in the title and assistive text.
An unavailable memory explanation names what is known instead of
"Unknown source": a powered-off guest reads "Unavailable while the
guest is powered off." MetricMiniSparkline gains an optional tooltip
so the chart covering the cell can carry that reason without changing
its accessible name.
75 lines
4.1 KiB
Python
75 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Verify safe existing-view guidance, not polling, routing or native recovery."""
|
|
|
|
from pathlib import Path
|
|
import unittest
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
HEADING = "### Current, retained and unavailable disk readings\n"
|
|
ANCHOR = "#current-retained-and-unavailable-disk-readings"
|
|
|
|
|
|
class GuestDiskReadingDocsTest(unittest.TestCase):
|
|
def section(self):
|
|
guide = (ROOT / "docs/VM_DISK_MONITORING.md").read_text(encoding="utf-8")
|
|
self.assertEqual(guide.count(HEADING), 1)
|
|
return " ".join(guide.split(HEADING, 1)[1].split("\n### ", 1)[0].split())
|
|
|
|
def test_explanations_use_existing_labels_without_claiming_freshness(self):
|
|
text = self.section()
|
|
row = (ROOT / "frontend-modern/src/components/Workloads/GuestRow.tsx").read_text()
|
|
drawer = (ROOT / "frontend-modern/src/components/Workloads/GuestDrawerOverview.tsx").read_text()
|
|
presentation = (ROOT / "frontend-modern/src/utils/workloadGuestPresentation.ts").read_text()
|
|
for label in ("Prior", "Last known", "No permission", "Agent error", "Denied", "Error"):
|
|
with self.subTest(label=label):
|
|
self.assertIn(label, text)
|
|
self.assertIn(f"'{label}'", row)
|
|
self.assertIn("Filesystems → Status", text)
|
|
self.assertIn("label: 'Filesystems'", drawer)
|
|
self.assertIn("makeDetailRow('Status'", drawer)
|
|
self.assertIn("Using last known disk stats", text)
|
|
self.assertIn("Using last known disk stats", presentation)
|
|
for distinction in ("not current free space", "unknown, not zero",
|
|
"not proof that the disk is full", "freshness unknown",
|
|
"A cooldown ending does not establish a successful new read"):
|
|
self.assertIn(distinction, text)
|
|
|
|
def test_inventory_workflow_does_not_confuse_selection_with_coverage(self):
|
|
text = self.section()
|
|
for distinction in ("not a monitoring-coverage check", "clear numeric disk conditions",
|
|
"existing name search or unfiltered inventory",
|
|
"same guest's explanation and filesystem rows",
|
|
"not evidence of low usage, deletion or healthy monitoring",
|
|
"neither changes access nor stops API polling",
|
|
"keep intentionally restricted targets restricted"):
|
|
self.assertIn(distinction, text)
|
|
|
|
def test_source_and_recovery_boundaries_remain_distinct(self):
|
|
text = self.section()
|
|
for distinction in ("existing linked Pulse Agent", "stale agent",
|
|
"same guest identity and filesystem",
|
|
"does not prove that the QEMU-only path recovered",
|
|
"without installing another agent", "normally collected observations",
|
|
"Do not run Diagnostics, guest-agent probes", "backup or a restart",
|
|
"Do not bypass a guest-read pause or widen token access",
|
|
"None of these display states proves thaw", "Backup safety"):
|
|
self.assertIn(distinction, text)
|
|
self.assertNotIn("```", text, "use existing observations, not an active command")
|
|
|
|
def test_existing_entry_points_reach_the_guidance_and_mirrors_match(self):
|
|
guide = (ROOT / "docs/VM_DISK_MONITORING.md").read_text()
|
|
diagnosis = guide.split("### A missing reading is not an installation diagnosis\n", 1)[1]
|
|
self.assertIn(f"[Check the reading's context]({ANCHOR})", diagnosis)
|
|
trouble = (ROOT / "docs/TROUBLESHOOTING.md").read_text()
|
|
dash_help = trouble.split('#### VMs show "-" for disk usage\n', 1)[1].split("\n#### ", 1)[0]
|
|
self.assertIn(f"VM_DISK_MONITORING.md{ANCHOR}", dash_help)
|
|
self.assertIn("A filtered list or disk sort is not proof of complete monitoring", dash_help)
|
|
for name in ("VM_DISK_MONITORING.md", "TROUBLESHOOTING.md"):
|
|
self.assertEqual((ROOT / "docs" / name).read_bytes(),
|
|
(ROOT / "frontend-modern/public/docs" / name).read_bytes())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|