109 lines
3.7 KiB
Python
109 lines
3.7 KiB
Python
"""Disk health rows: a dying drive must never render as a healthy one.
|
|
|
|
The agent reports drive health from two sources because neither covers the
|
|
fleet. MSFT_PhysicalDisk is the only one that reports NVMe - verified on a
|
|
two-NVMe box where the classic ATA SMART class returned zero instances while
|
|
both drives were present and healthy. Win32_DiskDrive covers ATA/SATA and hosts
|
|
where the Storage namespace is missing.
|
|
|
|
That means the panel can receive the same physical drive twice, from sources
|
|
that may disagree, plus rows where health could not be read at all. Every test
|
|
here pins a way this card could start showing a failing or unreadable drive as
|
|
fine, which is the only failure mode that matters: nobody investigates a disk
|
|
that looks healthy.
|
|
"""
|
|
|
|
from plugins.endpoints.api.routes import _diskhealth_rows
|
|
|
|
|
|
def _drive(deviceid, predictfailure, healthstatus='Healthy',
|
|
source='physicaldisk', model='Samsung SSD'):
|
|
return {
|
|
'deviceid': deviceid,
|
|
'model': model,
|
|
'mediatype': 'SSD',
|
|
'bustype': 'NVMe',
|
|
'healthstatus': healthstatus,
|
|
'predictfailure': predictfailure,
|
|
'source': source,
|
|
}
|
|
|
|
|
|
def test_a_failing_drive_sorts_above_healthy_ones():
|
|
"""On a multi-disk box the bad drive must not be below the fold."""
|
|
rows = _diskhealth_rows([
|
|
_drive('0', False),
|
|
_drive('1', True, healthstatus='Unhealthy'),
|
|
_drive('2', False),
|
|
])
|
|
|
|
assert [row['deviceid'] for row in rows] == ['1', '0', '2']
|
|
assert rows[0]['verdict'] == 'Failure predicted'
|
|
|
|
|
|
def test_a_drive_that_did_not_answer_reads_as_unknown_not_ok():
|
|
"""Null predictfailure is an unread drive, not a healthy one."""
|
|
rows = _diskhealth_rows([_drive('0', None, healthstatus='')])
|
|
|
|
assert rows[0]['verdict'] == 'Unknown'
|
|
assert rows[0]['healthstatus'] == 'Unknown'
|
|
|
|
|
|
def test_unknown_outranks_ok_so_silence_is_not_buried_under_health():
|
|
"""A drive that stopped answering is a weaker claim than one saying OK."""
|
|
rows = _diskhealth_rows([
|
|
_drive('0', False),
|
|
_drive('1', None),
|
|
])
|
|
|
|
assert [row['verdict'] for row in rows] == ['Unknown', 'OK']
|
|
|
|
|
|
def test_both_sources_survive_for_the_same_hardware():
|
|
"""Two disagreeing views of one drive is the signal, not noise.
|
|
|
|
Collapsing them would hide the case worth looking at: one source calling a
|
|
drive healthy while the other predicts failure.
|
|
"""
|
|
rows = _diskhealth_rows([
|
|
_drive('0', False, source='physicaldisk'),
|
|
_drive('0', True, healthstatus='Pred Fail', source='diskdrive'),
|
|
])
|
|
|
|
assert len(rows) == 2
|
|
assert {row['source'] for row in rows} == {'physicaldisk', 'diskdrive'}
|
|
assert rows[0]['verdict'] == 'Failure predicted'
|
|
|
|
|
|
def test_input_order_does_not_change_which_drive_is_shown_first():
|
|
"""The verdict ranking must decide the order, not arrival order."""
|
|
healthy = _drive('0', False)
|
|
failing = _drive('1', True)
|
|
|
|
forward = _diskhealth_rows([healthy, failing])
|
|
backward = _diskhealth_rows([failing, healthy])
|
|
|
|
assert forward == backward
|
|
assert forward[0]['deviceid'] == '1'
|
|
|
|
|
|
def test_an_nvme_drive_is_reported_rather_than_dropped():
|
|
"""The whole reason for the second source: ATA SMART returns nothing here."""
|
|
rows = _diskhealth_rows([_drive('0', False, source='physicaldisk')])
|
|
|
|
assert rows[0]['bustype'] == 'NVMe'
|
|
assert rows[0]['verdict'] == 'OK'
|
|
|
|
|
|
def test_a_malformed_payload_does_not_take_the_panel_down():
|
|
rows = _diskhealth_rows([_drive('0', False), 'not a dict', None])
|
|
|
|
assert len(rows) == 1
|
|
assert rows[0]['deviceid'] == '0'
|
|
|
|
|
|
def test_a_missing_or_wrong_shaped_payload_is_an_empty_panel():
|
|
assert _diskhealth_rows(None) == []
|
|
assert _diskhealth_rows({}) == []
|
|
assert _diskhealth_rows([]) == []
|