187 lines
6.7 KiB
Python
187 lines
6.7 KiB
Python
"""Mapped-drive merge: two disagreeing Windows sources into one honest row.
|
|
|
|
Windows reports mapped drives twice - Win32_NetworkConnection (the 'net use'
|
|
table) and Get-SmbMapping - and the two do not agree. Captured on one machine at
|
|
one moment, same two mappings, Get-SmbMapping said OK for both while net use
|
|
said Disconnected and Reconnecting. Trusting the structured source alone would
|
|
have rendered a healthy Q: on a box whose Q: was down.
|
|
|
|
So the probe collects both without reconciling them and _mapped_drives() decides
|
|
what an operator is shown. Every test here pins a way that decision could
|
|
silently start rendering a broken drive as a working one, which is the only
|
|
failure mode of this card that matters: nobody reports a drive that looks fine.
|
|
"""
|
|
|
|
from plugins.endpoints.api.routes import _mapped_drives
|
|
|
|
|
|
def _netuse(localname, remotename, status):
|
|
return {'localname': localname, 'remotename': remotename, 'status': status}
|
|
|
|
|
|
def _smb(localpath, remotepath, status):
|
|
return {'localpath': localpath, 'remotepath': remotepath, 'status': status}
|
|
|
|
|
|
def test_the_worse_of_two_disagreeing_sources_is_what_gets_shown():
|
|
"""The real capture: Get-SmbMapping says OK, net use says Disconnected.
|
|
|
|
The drive was down. Showing OK because one source said so is the exact bug
|
|
this merge exists to prevent.
|
|
"""
|
|
rows = _mapped_drives({
|
|
'netuse': [_netuse('Q:', r'\\server\specdata', 'Disconnected')],
|
|
'smbmapping': [_smb('Q:', r'\\server\specdata', 'OK')],
|
|
})
|
|
|
|
assert rows == [r'Q: \\server\specdata (Disconnected)']
|
|
|
|
|
|
def test_reconnecting_is_worse_than_ok_and_survives_the_merge():
|
|
"""Reconnecting is a real status from the capture, not a synonym for OK."""
|
|
rows = _mapped_drives({
|
|
'netuse': [_netuse('S:', r'\\server\shared', 'Reconnecting')],
|
|
'smbmapping': [_smb('S:', r'\\server\shared', 'OK')],
|
|
})
|
|
|
|
assert rows == [r'S: \\server\shared (Reconnecting)']
|
|
|
|
|
|
def test_a_drive_both_sources_call_healthy_is_not_annotated():
|
|
"""Only problems are labelled; tagging every drive '(OK)' buries the bad one."""
|
|
rows = _mapped_drives({
|
|
'netuse': [_netuse('H:', r'\\server\home', 'OK')],
|
|
'smbmapping': [_smb('H:', r'\\server\home', 'OK')],
|
|
})
|
|
|
|
assert rows == [r'H: \\server\home']
|
|
|
|
|
|
def test_a_drive_only_one_source_knows_about_is_still_reported():
|
|
"""Get-SmbMapping is absent on some builds and session types.
|
|
|
|
Requiring agreement between the sources would hide every mapped drive on
|
|
those machines rather than showing what is known about them.
|
|
"""
|
|
rows = _mapped_drives({
|
|
'netuse': [_netuse('P:', r'\\server\programs', 'Disconnected')],
|
|
'smbmapping': [],
|
|
})
|
|
|
|
assert rows == [r'P: \\server\programs (Disconnected)']
|
|
|
|
|
|
def test_the_smbmapping_key_missing_entirely_degrades_to_netuse():
|
|
"""Old agents predate the second source; the panel must still work.
|
|
|
|
The server ships ahead of the agent republish, so this is the live shape
|
|
until every endpoint has the new probe.
|
|
"""
|
|
rows = _mapped_drives({
|
|
'netuse': [_netuse('Q:', r'\\server\specdata', 'OK')],
|
|
})
|
|
|
|
assert rows == [r'Q: \\server\specdata']
|
|
|
|
|
|
def test_a_drive_with_no_status_from_either_source_reads_as_unknown():
|
|
"""A blank annotation reads as healthy, so a failed check must not be blank."""
|
|
rows = _mapped_drives({
|
|
'netuse': [_netuse('Z:', r'\\server\scratch', None)],
|
|
'smbmapping': [],
|
|
})
|
|
|
|
assert rows == [r'Z: \\server\scratch (Unknown)']
|
|
|
|
|
|
def test_an_unrecognised_status_is_not_assumed_healthy():
|
|
"""Unknown vocabulary ranks below OK deliberately.
|
|
|
|
Paired against OK specifically: a status the server does not recognise must
|
|
LOSE to a healthy one, or an unseen fault renders green. Pairing it against
|
|
a known-bad status would prove nothing, since the known-bad value would win
|
|
however unknowns are ranked.
|
|
"""
|
|
rows = _mapped_drives({
|
|
'netuse': [_netuse('X:', r'\\server\thing', 'SomeNewStatus')],
|
|
'smbmapping': [_smb('X:', r'\\server\thing', 'OK')],
|
|
})
|
|
|
|
assert rows == [r'X: \\server\thing (SomeNewStatus)']
|
|
|
|
|
|
def test_a_known_bad_status_beats_an_unrecognised_one():
|
|
"""Unavailable outranks an unknown string; the worst named state wins."""
|
|
rows = _mapped_drives({
|
|
'netuse': [_netuse('X:', r'\\server\thing', 'Unavailable')],
|
|
'smbmapping': [_smb('X:', r'\\server\thing', 'SomeNewStatus')],
|
|
})
|
|
|
|
assert rows == [r'X: \\server\thing (Unavailable)']
|
|
|
|
|
|
def test_which_source_reported_a_status_does_not_change_the_verdict():
|
|
"""The same pair of statuses must resolve identically whichever side sent it.
|
|
|
|
_worse_drive_status ranks by severity and breaks ties by argument order, so
|
|
if two statuses ever rank EQUAL the answer silently depends on which source
|
|
happened to report which - and a drive would read healthy or broken based on
|
|
enumeration order. Asserting both directions is what makes an accidental tie
|
|
visible; a single-direction test passes on luck.
|
|
"""
|
|
remote = r'\\server\thing'
|
|
pairs = [
|
|
('OK', 'Disconnected'),
|
|
('OK', 'SomeNewStatus'),
|
|
('Reconnecting', 'Unavailable'),
|
|
('OK', 'Reconnecting'),
|
|
]
|
|
|
|
for first, second in pairs:
|
|
forward = _mapped_drives({
|
|
'netuse': [_netuse('X:', remote, first)],
|
|
'smbmapping': [_smb('X:', remote, second)],
|
|
})
|
|
backward = _mapped_drives({
|
|
'netuse': [_netuse('X:', remote, second)],
|
|
'smbmapping': [_smb('X:', remote, first)],
|
|
})
|
|
assert forward == backward, (
|
|
'statuses {!r}/{!r} resolve differently depending on which source '
|
|
'reported them'.format(first, second))
|
|
|
|
|
|
def test_the_two_sources_are_paired_by_drive_letter_not_by_order():
|
|
"""The sources enumerate independently and need not agree on ordering."""
|
|
rows = _mapped_drives({
|
|
'netuse': [
|
|
_netuse('Q:', r'\\server\specdata', 'OK'),
|
|
_netuse('S:', r'\\server\shared', 'OK'),
|
|
],
|
|
'smbmapping': [
|
|
_smb('S:', r'\\server\shared', 'Disconnected'),
|
|
_smb('Q:', r'\\server\specdata', 'OK'),
|
|
],
|
|
})
|
|
|
|
assert rows == [
|
|
r'Q: \\server\specdata',
|
|
r'S: \\server\shared (Disconnected)',
|
|
]
|
|
|
|
|
|
def test_no_user_context_at_all_yields_no_rows():
|
|
"""Nobody signed in is a valid state, not a fault."""
|
|
assert _mapped_drives({}) == []
|
|
|
|
|
|
def test_malformed_entries_are_skipped_rather_than_raising():
|
|
"""The payload is agent-supplied; a bad row must not blank the whole card."""
|
|
rows = _mapped_drives({
|
|
'netuse': ['not-a-dict', None, {'status': 'OK'},
|
|
_netuse('Q:', r'\\server\specdata', 'Disconnected')],
|
|
'smbmapping': 'not-a-list',
|
|
})
|
|
|
|
assert rows == [r'Q: \\server\specdata (Disconnected)']
|