Match the optional identifiers in every list's search box
This commit is contained in:
@@ -375,6 +375,11 @@ def list_computers():
|
||||
Asset.assetnumber.ilike(pattern),
|
||||
Asset.name.ilike(pattern),
|
||||
Asset.serialnumber.ilike(pattern),
|
||||
# The optional identifiers too (ADR-001). Global search matches
|
||||
# these, and a tag read off the machine has to find it here as
|
||||
# well - this box is where someone holding the label looks.
|
||||
Asset.gaugelabreference.ilike(pattern),
|
||||
Asset.maintenancereference.ilike(pattern),
|
||||
Computer.hostname.ilike(pattern),
|
||||
ComputerType.computertype.ilike(pattern)
|
||||
)
|
||||
|
||||
@@ -189,6 +189,11 @@ def list_machines():
|
||||
Asset.assetnumber.ilike(pattern),
|
||||
Asset.name.ilike(pattern),
|
||||
Asset.serialnumber.ilike(pattern),
|
||||
# The optional identifiers too (ADR-001). Global search matches
|
||||
# these, and a tag read off the machine has to find it here as
|
||||
# well - this box is where someone holding the label looks.
|
||||
Asset.gaugelabreference.ilike(pattern),
|
||||
Asset.maintenancereference.ilike(pattern),
|
||||
MachineType.machinetype.ilike(pattern),
|
||||
Vendor.vendor.ilike(pattern)
|
||||
)
|
||||
|
||||
@@ -179,6 +179,11 @@ def list_tools():
|
||||
Asset.assetnumber.ilike(pattern),
|
||||
Asset.name.ilike(pattern),
|
||||
Asset.serialnumber.ilike(pattern),
|
||||
# The optional identifiers too (ADR-001). Global search matches
|
||||
# these, and a tag read off the machine has to find it here as
|
||||
# well - this box is where someone holding the label looks.
|
||||
Asset.gaugelabreference.ilike(pattern),
|
||||
Asset.maintenancereference.ilike(pattern),
|
||||
MeasuringToolType.name.ilike(pattern),
|
||||
))
|
||||
if type_id := request.args.get('typeid', type=int):
|
||||
|
||||
@@ -223,6 +223,11 @@ def list_network_devices():
|
||||
Asset.assetnumber.ilike(pattern),
|
||||
Asset.name.ilike(pattern),
|
||||
Asset.serialnumber.ilike(pattern),
|
||||
# The optional identifiers too (ADR-001). Global search matches
|
||||
# these, and a tag read off the machine has to find it here as
|
||||
# well - this box is where someone holding the label looks.
|
||||
Asset.gaugelabreference.ilike(pattern),
|
||||
Asset.maintenancereference.ilike(pattern),
|
||||
NetworkDevice.hostname.ilike(pattern),
|
||||
NetworkDeviceType.networkdevicetype.ilike(pattern),
|
||||
Vendor.vendor.ilike(pattern)
|
||||
|
||||
@@ -254,6 +254,11 @@ def list_printers():
|
||||
Asset.assetnumber.ilike(pattern),
|
||||
Asset.name.ilike(pattern),
|
||||
Asset.serialnumber.ilike(pattern),
|
||||
# The optional identifiers too (ADR-001). Global search matches
|
||||
# these, and a tag read off the machine has to find it here as
|
||||
# well - this box is where someone holding the label looks.
|
||||
Asset.gaugelabreference.ilike(pattern),
|
||||
Asset.maintenancereference.ilike(pattern),
|
||||
Printer.hostname.ilike(pattern),
|
||||
Printer.windowsname.ilike(pattern),
|
||||
PrinterType.printertype.ilike(pattern),
|
||||
|
||||
84
tests/test_core/test_list_search_identifiers.py
Normal file
84
tests/test_core/test_list_search_identifiers.py
Normal file
@@ -0,0 +1,84 @@
|
||||
"""Every asset list's search box matches the optional identifiers (ADR-001).
|
||||
|
||||
Settings offers `gaugelabreference` and `maintenancereference` on machines, PCs,
|
||||
printers, network devices and measuring tools. Both were shown on the form and
|
||||
the detail page and neither was matched by any list's `?search=`, so someone
|
||||
holding a physical tag could read it, type it into the list they were already
|
||||
looking at, and get nothing - while global search found it.
|
||||
|
||||
One parametrized test over all five lists on purpose. The search clause is
|
||||
copy-pasted five times, once per plugin, which is exactly how all five came to
|
||||
omit a field their forms collect; a per-plugin test would drift the same way.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from shopdb.core.models import Asset, AssetType
|
||||
|
||||
|
||||
# (list endpoint, create endpoint, assettype)
|
||||
LISTS = [
|
||||
('/api/machines', '/api/machines', 'machine'),
|
||||
('/api/computers', '/api/computers', 'computer'),
|
||||
('/api/printers', '/api/printers', 'printer'),
|
||||
('/api/network', '/api/network', 'network_device'),
|
||||
('/api/measuringtools', '/api/measuringtools', 'measuring_tool'),
|
||||
]
|
||||
|
||||
|
||||
def _seed(client, db, auth_headers, createpath, assettype, assetnumber):
|
||||
"""Create one record of this type carrying both identifiers."""
|
||||
if not AssetType.query.filter_by(assettype=assettype).first():
|
||||
db.session.add(AssetType(assettype=assettype, pluginname=assettype,
|
||||
tablename=assettype, description=assettype))
|
||||
db.session.commit()
|
||||
|
||||
resp = client.post(createpath, json={'assetnumber': assetnumber},
|
||||
headers=auth_headers)
|
||||
assert resp.status_code == 201, (createpath, resp.get_json())
|
||||
|
||||
asset = Asset.query.filter_by(assetnumber=assetnumber).first()
|
||||
asset.gaugelabreference = f'ZZG{assetnumber}'
|
||||
asset.maintenancereference = f'ZZM{assetnumber}'
|
||||
db.session.commit()
|
||||
return asset
|
||||
|
||||
|
||||
def _numbers(client, auth_headers, listpath, query):
|
||||
"""Asset numbers a list returns for a search term."""
|
||||
resp = client.get(f'{listpath}?search={query}', headers=auth_headers)
|
||||
assert resp.status_code == 200, (listpath, resp.get_json())
|
||||
found = []
|
||||
for row in resp.get_json()['data']:
|
||||
# Lists differ in shape; the asset number is the field all of them
|
||||
# carry, either directly or on a nested asset.
|
||||
found.append(row.get('assetnumber')
|
||||
or (row.get('asset') or {}).get('assetnumber'))
|
||||
return [f for f in found if f]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('listpath,createpath,assettype', LISTS)
|
||||
def test_a_list_search_finds_a_gauge_lab_reference(client, db, auth_headers,
|
||||
listpath, createpath, assettype):
|
||||
assetnumber = f'ZZ{assettype[:4].upper()}01'
|
||||
_seed(client, db, auth_headers, createpath, assettype, assetnumber)
|
||||
assert assetnumber in _numbers(client, auth_headers, listpath,
|
||||
f'ZZG{assetnumber}')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('listpath,createpath,assettype', LISTS)
|
||||
def test_a_list_search_finds_a_maintenance_reference(client, db, auth_headers,
|
||||
listpath, createpath, assettype):
|
||||
assetnumber = f'ZZ{assettype[:4].upper()}02'
|
||||
_seed(client, db, auth_headers, createpath, assettype, assetnumber)
|
||||
assert assetnumber in _numbers(client, auth_headers, listpath,
|
||||
f'ZZM{assetnumber}')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('listpath,createpath,assettype', LISTS)
|
||||
def test_a_list_search_still_excludes_a_non_match(client, db, auth_headers,
|
||||
listpath, createpath, assettype):
|
||||
"""Widening the clause must not turn the search box into a pass-through."""
|
||||
assetnumber = f'ZZ{assettype[:4].upper()}03'
|
||||
_seed(client, db, auth_headers, createpath, assettype, assetnumber)
|
||||
assert _numbers(client, auth_headers, listpath, 'ZZNOTHINGMATCHESTHIS') == []
|
||||
Reference in New Issue
Block a user