Toggle a Diagnostics panel with i, built on the Activity readout. It swaps in for the Drive pane and shows the decoded critical_warning, power-on hours, power cycles, unsafe shutdowns, media errors and available spare with their change over the selection, and per-hour (Day) or per-day (History) temperature min/avg/max, active/idle/powered-off/unknown split and coverage. History bars draw reads beside writes while it is open, and a set critical_warning shows as a badge in the endurance outlook without affecting the projection. Counter deltas are withheld across a controller segment change.
155 lines
5.4 KiB
Python
155 lines
5.4 KiB
Python
"""Diagnostics panel on the dashboard (issue #109): toggle, render, badge."""
|
|
import sqlite3
|
|
|
|
import pytest
|
|
from test_dashboard_design import dashboard, visible # noqa: F401 (fixtures)
|
|
|
|
from fenris.activity_plot import VolumePoint
|
|
from fenris.tui import FenrisTuiApp, HelpScreen, HistoryGraph
|
|
|
|
|
|
def _store(app):
|
|
return sqlite3.connect(app.store_path)
|
|
|
|
|
|
def _set_latest_warning(app, value):
|
|
conn = _store(app)
|
|
conn.execute(
|
|
"UPDATE samples SET critical_warning = ?, power_on_hours = id, "
|
|
"unsafe_shutdowns = id / 20 WHERE 1", (value,))
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
|
|
async def _settle(app, pilot):
|
|
app.on_refresh_tick()
|
|
await pilot.pause()
|
|
|
|
|
|
def _text(app, selector):
|
|
return str(app.query_one(selector).render())
|
|
|
|
|
|
def test_i_is_a_declared_binding_and_d_stays_disclosures():
|
|
keys = {b.key: b.action for b in FenrisTuiApp.BINDINGS}
|
|
assert keys["i"] == "toggle_diagnostics"
|
|
assert keys["d"] == "disclose"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("size", [(140, 44), (100, 30)])
|
|
async def test_i_toggles_the_diagnostics_panel_and_hides_the_drive_pane(dashboard, size): # noqa: F811
|
|
app = dashboard
|
|
_set_latest_warning(app, 0)
|
|
async with app.run_test(size=size) as pilot:
|
|
await _settle(app, pilot)
|
|
assert not app.query_one("#diagnostics-panel").display
|
|
assert app.query_one("#drive-panel").display
|
|
await pilot.press("i")
|
|
await _settle(app, pilot)
|
|
assert app.query_one("#diagnostics-panel").display
|
|
assert not app.query_one("#drive-panel").display
|
|
body = _text(app, "#diagnostics")
|
|
assert "Diagnostics" in body and "Critical warning none" in body
|
|
assert "Power-on hours 61 Δ +60" in body
|
|
await pilot.press("i")
|
|
await _settle(app, pilot)
|
|
assert not app.query_one("#diagnostics-panel").display
|
|
assert app.query_one("#drive-panel").display
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_footer_and_help_list_the_diagnostics_key(dashboard): # noqa: F811
|
|
app = dashboard
|
|
async with app.run_test(size=(140, 40)) as pilot:
|
|
await _settle(app, pilot)
|
|
assert "i Diagnostics" in _text(app, "#action-rail")
|
|
await pilot.press("?")
|
|
assert isinstance(app.screen, HelpScreen)
|
|
assert "Diagnostics" in str(app.screen.query_one("#help-text").render())
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_diagnostics_follow_the_activity_view(dashboard): # noqa: F811
|
|
app = dashboard
|
|
async with app.run_test(size=(140, 44)) as pilot:
|
|
await _settle(app, pilot)
|
|
await pilot.press("i")
|
|
await _settle(app, pilot)
|
|
assert "last 3h" in _text(app, "#diagnostics")
|
|
await pilot.press("v") # Day
|
|
await _settle(app, pilot)
|
|
body = _text(app, "#diagnostics")
|
|
assert "· day 20" in body and "Hours ·" in body
|
|
await pilot.press("v") # History
|
|
await _settle(app, pilot)
|
|
assert "last 14 days" in _text(app, "#diagnostics")
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_critical_warning_badge_shows_in_the_outlook_without_the_panel(dashboard): # noqa: F811
|
|
app = dashboard
|
|
_set_latest_warning(app, 0x04)
|
|
async with app.run_test(size=(140, 44)) as pilot:
|
|
await _settle(app, pilot)
|
|
assert not app.query_one("#diagnostics-panel").display
|
|
band = _text(app, "#headline-band")
|
|
assert "0x04" in band and "reliability degraded" in band
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_no_badge_when_the_drive_reports_no_warning(dashboard): # noqa: F811
|
|
app = dashboard
|
|
_set_latest_warning(app, 0)
|
|
async with app.run_test(size=(140, 44)) as pilot:
|
|
await _settle(app, pilot)
|
|
assert "critical warning" not in _text(app, "#headline-band").lower()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_diagnostics_work_in_constrained_mode(dashboard): # noqa: F811
|
|
app = dashboard
|
|
_set_latest_warning(app, 0x01)
|
|
async with app.run_test(size=(60, 20)) as pilot:
|
|
await _settle(app, pilot)
|
|
assert app._is_constrained_mode
|
|
await pilot.press("i")
|
|
await _settle(app, pilot)
|
|
assert app.query_one("#diagnostics-panel").display
|
|
body = _text(app, "#diagnostics")
|
|
assert "available spare below threshold" in body
|
|
assert "Power-on hours" in body
|
|
await pilot.press("i")
|
|
await _settle(app, pilot)
|
|
assert app.query_one("#drive-panel").display
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_toggling_while_zoomed_restores_the_grid_and_keeps_focus(dashboard): # noqa: F811
|
|
app = dashboard
|
|
async with app.run_test(size=(140, 44)) as pilot:
|
|
await _settle(app, pilot)
|
|
await pilot.press("z")
|
|
await pilot.press("i")
|
|
await _settle(app, pilot)
|
|
assert app._zoomed_panel is None
|
|
assert app.focused is not None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_history_bars_draw_reads_alongside_writes_only_with_diagnostics(dashboard): # noqa: F811
|
|
app = dashboard
|
|
async with app.run_test(size=(140, 44)) as pilot:
|
|
await _settle(app, pilot)
|
|
await pilot.press("v", "v") # History
|
|
await _settle(app, pilot)
|
|
graph = app.query_one(HistoryGraph)
|
|
assert "Reads" not in _text(app, "#bar-legend")
|
|
await pilot.press("i")
|
|
await _settle(app, pilot)
|
|
legend = _text(app, "#bar-legend")
|
|
assert "Writes" in legend and "Reads" in legend
|
|
await pilot.press("i")
|
|
await _settle(app, pilot)
|
|
assert "Reads" not in _text(app, "#bar-legend")
|