The board was one card per source in a fixed grid: every source got the same small box whatever it had to say (warranties showed 5 of 50), and a box per source flattened priority, while the largest type on the page belonged to counts that need nobody. Now a severity rollup, one worst-first queue of everything needing a person, and a row of context beneath. The queue is full width, capped per source so a noisy check cannot bury a rare one, and names what did not fit with a link to it. Chips filter the queue by check as well as by severity; both narrow what is already loaded, so the counts and rows cannot disagree. Dropped: an 'All assets' tile shown beside its own four addends, a printer strip carrying the same count a third time, three cards whose job was to display 0, and a Recent Devices table listing five machines all 'In Use'. Contract 0.26.0 adds optional 'shortname' on dashboard cards - a title is written as a heading and ran wider than the hostname it qualified as a row badge. Also: the supplies card reported 'Low Supplies 0' when Zabbix was unreachable, which reads as reassurance rather than the truth that nothing could see the cartridges. It now distinguishes unreachable (says so) from unconfigured (stays quiet - the site declined the feature) from a real zero. Full suite 2182 passed, frontend 314 passed.
91 lines
3.4 KiB
Python
91 lines
3.4 KiB
Python
"""The supplies dashboard card must not report "nothing low" when it cannot see.
|
|
|
|
_get_low_supplies_data returned the same empty result for three different
|
|
situations - Zabbix not configured, Zabbix unreachable, and every cartridge
|
|
full - so the dashboard displayed "Low Supplies 0 / Critical 0" while the
|
|
monitoring was dead. That is not a missing feature; it is a wrong statement, and
|
|
it reads as reassurance.
|
|
|
|
These pin the three cases apart.
|
|
"""
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
from shopdb.api import db
|
|
from shopdb.core.models import Setting
|
|
|
|
|
|
def _call(client, auth_headers):
|
|
response = client.get('/api/printers/dashboard/supplies', headers=auth_headers)
|
|
assert response.status_code == 200
|
|
return response.get_json()['data']
|
|
|
|
|
|
class FakeService:
|
|
def __init__(self, configured, reachable):
|
|
self.isconfigured = configured
|
|
self.isreachable = reachable
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _clear_cache(app):
|
|
from shopdb.extensions import cache
|
|
cache.delete('printers_low_supplies')
|
|
yield
|
|
cache.delete('printers_low_supplies')
|
|
|
|
|
|
def test_unreachable_says_so_rather_than_reporting_zero(client, auth_headers):
|
|
"""Configured and unanswerable: the cartridges are NOT known to be fine."""
|
|
with patch('plugins.printers.api.asset_routes.ZabbixService',
|
|
return_value=FakeService(configured=True, reachable=False)):
|
|
data = _call(client, auth_headers)
|
|
|
|
assert data['rows'] == []
|
|
assert data['unavailable'] == 'Supply monitoring is not reachable'
|
|
|
|
|
|
def test_unconfigured_stays_quiet(client, auth_headers):
|
|
"""The site did not ask for supply monitoring.
|
|
|
|
A permanent "not configured" line would be a card reporting nothing wrong
|
|
every day, which is how a board teaches people to stop reading it. It has
|
|
nothing to say, so it says nothing and the card hides.
|
|
"""
|
|
with patch('plugins.printers.api.asset_routes.ZabbixService',
|
|
return_value=FakeService(configured=False, reachable=False)):
|
|
data = _call(client, auth_headers)
|
|
|
|
assert data['rows'] == []
|
|
assert data.get('unavailable') is None
|
|
|
|
|
|
def test_reachable_with_nothing_low_is_not_flagged_as_blind(client, auth_headers):
|
|
"""Zabbix answered and every cartridge is fine. That is a real zero."""
|
|
with patch('plugins.printers.api.asset_routes._get_low_supplies_data',
|
|
return_value={'printers': [],
|
|
'summary': {'total_checked': 3, 'low': 0, 'critical': 0}}):
|
|
data = _call(client, auth_headers)
|
|
|
|
assert data['rows'] == []
|
|
assert data.get('unavailable') is None
|
|
|
|
|
|
def test_the_envelope_carries_rows_so_the_card_can_still_render(client, auth_headers):
|
|
"""The response became an envelope to carry the reason; rows must survive."""
|
|
printer = {
|
|
'printerid': 1, 'assetnumber': 'PRN-1', 'printername': 'Front office',
|
|
'location': 'Bay 3', 'mapx': None, 'mapy': None, 'levelid': None,
|
|
'supplies': [{'name': 'Black', 'remaining': 2, 'status': 'critical'}],
|
|
}
|
|
with patch('plugins.printers.api.asset_routes._get_low_supplies_data',
|
|
return_value={'printers': [printer],
|
|
'summary': {'total_checked': 1, 'low': 1, 'critical': 1}}):
|
|
data = _call(client, auth_headers)
|
|
|
|
assert data.get('unavailable') is None
|
|
assert len(data['rows']) == 1
|
|
assert data['rows'][0]['printername'] == 'Front office'
|
|
assert data['rows'][0]['iscritical'] is True
|