Volume capacity and physical drive health were two adjacent cards, and the operator reading a full disk is usually the operator reading a dying disk in the same minute. They are now one Storage card with two sections. Visual grouping only - the two tables share no key, storage being per volume and health per physical device, and one drive can back several volumes or none the operator sees. Nothing is reconciled across the sections; this is not the mapped-drive merge where two sources described the same drive and the worse status won. The tabs render type was the only sections-in-one-card mechanism and emitted label/value fields with no table path, so it now takes table sections too. That is the renderer every plugin uses, so both behaviour changes in it are mutation-tested. Two things only surfaced on contact: the empty-section filter had to grow a table branch, because a table section declares columns up front and dropping it when it has no rows takes its tab with it and reads as no disks rather than nothing reported; and full-width span was keyed off the declared render type, but a tabs panel holding a six-column table needs the same span and that is only knowable from fetched data. The diskhealth route stays. It no longer backs a panel, but it is a stable read for callers outside the renderer and removing it for a UI-only change would break them.
71 lines
2.7 KiB
Python
71 lines
2.7 KiB
Python
"""The Monitors tab split: a panel in a group no tab renders disappears.
|
|
|
|
This has silently eaten cards twice - once when tracked services moved out of
|
|
'actions', once on the 'metrics' to 'monitors' rename. Both times the backend
|
|
named a group the frontend did not render, and the panel was not shown, not
|
|
logged, and not missed until someone went looking for it.
|
|
|
|
The split is only correct if four places agree, and only two of them are Python:
|
|
1. the panels' group here
|
|
2. RENDERED_GROUPS in PluginAssetPanels.vue
|
|
3. the tab label map in PCDetail.vue
|
|
4. the v-show block that gives the tab a layout
|
|
|
|
These tests pin the Python half so a later edit cannot quietly move a panel into
|
|
a group nothing renders. The frontend half is pinned by its own spec.
|
|
"""
|
|
|
|
from plugins.endpoints.plugin import EndpointsPlugin
|
|
|
|
|
|
# Must match RENDERED_GROUPS in frontend/src/components/PluginAssetPanels.vue.
|
|
# A panel in any group not listed here is fetched, held, and shown nowhere.
|
|
RENDERED_GROUPS = {'details', 'monitors', 'serviceprocess', 'software',
|
|
'activity'}
|
|
|
|
|
|
def _panels():
|
|
return {panel['id']: panel for panel in EndpointsPlugin().get_asset_panels()}
|
|
|
|
|
|
def test_no_panel_lands_in_a_group_the_frontend_does_not_render():
|
|
"""The failure mode that ate cards twice: a group with no tab."""
|
|
for panel in EndpointsPlugin().get_asset_panels():
|
|
group = panel.get('group', 'details')
|
|
assert group in RENDERED_GROUPS, (
|
|
f"panel {panel['id']} is in group {group!r}, which no tab renders"
|
|
)
|
|
|
|
|
|
def test_tracked_services_and_processes_moved_to_their_own_group():
|
|
panels = _panels()
|
|
|
|
assert panels['endpoints-tracked-services']['group'] == 'serviceprocess'
|
|
assert panels['endpoints-tracked-processes']['group'] == 'serviceprocess'
|
|
|
|
|
|
def test_the_service_process_tab_is_not_left_empty():
|
|
"""A tab whose panels all moved away reads as broken, not as absent."""
|
|
groups = [panel.get('group', 'details')
|
|
for panel in EndpointsPlugin().get_asset_panels()]
|
|
|
|
assert 'serviceprocess' in groups
|
|
|
|
|
|
def test_system_monitors_keeps_panels_of_its_own():
|
|
"""The rename is only safe if Monitors still has content after the move."""
|
|
groups = [panel.get('group', 'details')
|
|
for panel in EndpointsPlugin().get_asset_panels()]
|
|
|
|
assert 'monitors' in groups
|
|
|
|
|
|
def test_disk_health_stayed_with_the_system_health_panels():
|
|
"""Disk health is the box's own health, not something running on it.
|
|
|
|
It is now a section of the Storage card rather than a panel of its own,
|
|
so the group assertion follows it there.
|
|
"""
|
|
assert 'endpoints-diskhealth' not in _panels()
|
|
assert _panels()['endpoints-storage']['group'] == 'monitors'
|