diff --git a/plugins/printers/api/asset_routes.py b/plugins/printers/api/asset_routes.py index 46813f00..da463726 100644 --- a/plugins/printers/api/asset_routes.py +++ b/plugins/printers/api/asset_routes.py @@ -2129,9 +2129,14 @@ def _get_low_supplies_data(): # dashboard then showed Low Supplies 0 while the monitoring was dead, which # is not a missing feature but a wrong statement: it reads as reassurance. if not service.isconfigured: - return {'printers': [], 'unavailable': 'Supply monitoring is not configured', - 'summary': {'total_checked': 0, 'low': 0, 'critical': 0}} + # Enabled plus a URL plus a token. Absent any of those the site has not + # asked for supply monitoring, and 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. Nothing to say: stay hidden. + return {'printers': [], 'summary': {'total_checked': 0, 'low': 0, 'critical': 0}} if not service.isreachable: + # Configured and unanswerable is a different thing: something meant to + # work is not working, and the cartridges are NOT known to be fine. return {'printers': [], 'unavailable': 'Supply monitoring is not reachable', 'summary': {'total_checked': 0, 'low': 0, 'critical': 0}} diff --git a/tests/test_plugins/test_supplies_card_blindness.py b/tests/test_plugins/test_supplies_card_blindness.py new file mode 100644 index 00000000..1e766a24 --- /dev/null +++ b/tests/test_plugins/test_supplies_card_blindness.py @@ -0,0 +1,90 @@ +"""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