Files
shopdb-flask/tests/test_plugins/test_printer_driver_resolution.py

178 lines
8.2 KiB
Python

"""Which driver a printer installs with.
One row per model was unworkable: HP and Xerox universal drivers cover 41 of the
reference site's 44 printers, so binding a driver to a single model meant 21
near-duplicate rows pointing at one package - a table nobody keeps true, and the
reason 42 of 44 printers could not resolve a driver at all.
The order is most-specific-first, and each step exists for a printer that really
is on this floor: a plotter and a card printer need their own driver, everything
else takes its make's universal one.
"""
import pytest
from shopdb.core.models import Vendor, Model
from plugins.printers.models import Printer, PrinterDriver
from plugins.printers.api.asset_routes import _printer_driver
def _universal():
return (PrinterDriver.query
.filter(PrinterDriver.modelnumberid.is_(None),
PrinterDriver.isactive == True)
.order_by(PrinterDriver.name).all())
@pytest.fixture
def fleet(db):
hp = Vendor(vendor='HP')
xerox = Vendor(vendor='Xerox')
db.session.add_all([hp, xerox])
db.session.flush()
laserjet = Model(modelnumber='LaserJet M602', vendorid=hp.vendorid)
designjet = Model(modelnumber='DesignJet T1700', vendorid=hp.vendorid)
db.session.add_all([laserjet, designjet])
db.session.flush()
upd = PrinterDriver(name='HP Universal Print Driver', drivername='HP Universal Printing PS',
location=r'\\server\share\hp_upd', vendorid=hp.vendorid, isactive=True)
plotter = PrinterDriver(name='HP DesignJet T1700', drivername='HP DesignJet T1700dr V4',
location=r'\\server\share\designjet', vendorid=hp.vendorid,
modelnumberid=designjet.modelnumberid, isactive=True)
gpd = PrinterDriver(name='Xerox Global Print Driver PCL6',
drivername='Xerox Global Print Driver PCL6',
location=r'\\server\share\xerox', vendorid=xerox.vendorid, isactive=True)
db.session.add_all([upd, plotter, gpd])
db.session.commit()
return {'hp': hp, 'xerox': xerox, 'laserjet': laserjet, 'designjet': designjet,
'upd': upd, 'plotter': plotter, 'gpd': gpd}
def test_a_printer_takes_its_makes_universal_driver(fleet):
"""The case that covers most of a floor: no per-model row exists, and none
should have to."""
printer = Printer(vendorid=fleet['hp'].vendorid, modelnumberid=fleet['laserjet'].modelnumberid)
assert _printer_driver(printer, _universal()).name == 'HP Universal Print Driver'
def test_a_model_specific_driver_beats_the_universal_one(fleet):
"""A plotter is not a LaserJet. If the universal driver won here, the
DesignJet would be installed with a driver that cannot drive it."""
printer = Printer(vendorid=fleet['hp'].vendorid, modelnumberid=fleet['designjet'].modelnumberid)
assert _printer_driver(printer, _universal()).name == 'HP DesignJet T1700'
def test_vendors_do_not_bleed_into_each_other(fleet):
"""A Xerox must never resolve to the HP driver, whatever the ordering."""
printer = Printer(vendorid=fleet['xerox'].vendorid, modelnumberid=None)
assert _printer_driver(printer, _universal()).name == 'Xerox Global Print Driver PCL6'
def test_a_printer_with_no_vendor_resolves_to_nothing(fleet):
"""Better nothing than a guess: installing the wrong driver is worse than
reporting that a printer has none."""
printer = Printer(vendorid=None, modelnumberid=None)
assert _printer_driver(printer, _universal()) is None
def test_a_make_with_no_driver_row_resolves_to_nothing(db, fleet):
"""A vendor nobody has added a driver for is unresolved, not misresolved."""
zebra = Vendor(vendor='Zebra')
db.session.add(zebra)
db.session.commit()
printer = Printer(vendorid=zebra.vendorid, modelnumberid=None)
assert _printer_driver(printer, _universal()) is None
def test_the_pre_vendorid_naming_convention_still_resolves(db, fleet):
"""A site that populated printerdrivers before the column existed matched on
the vendor word in the driver's NAME. That must keep working, or an upgrade
silently takes every driver away."""
epson = Vendor(vendor='Epson')
db.session.add(epson)
db.session.flush()
db.session.add(PrinterDriver(name='Epson ColorWorks universal', drivername='EPSON TM-C3500',
location=r'\\server\share\epson', isactive=True))
db.session.commit()
# vendor attached, not just vendorid: the legacy path reads the vendor's
# NAME, which only exists through the relationship.
printer = Printer(vendorid=epson.vendorid, modelnumberid=None)
printer.vendor = epson
assert _printer_driver(printer, _universal()).name == 'Epson ColorWorks universal'
def test_a_row_that_names_a_vendor_is_not_matched_by_its_text(db, fleet):
"""A driver whose vendorid is set and does NOT match must not then be picked
up by the name convention: a mis-set vendor would resolve to the wrong
package, which is worse than resolving to none."""
brother = Vendor(vendor='Brother')
db.session.add(brother)
db.session.flush()
# Named for Brother, but bound to HP by id - the id is the truth.
db.session.add(PrinterDriver(name='Brother universal', drivername='Brother Universal',
location=r'\\server\share\brother',
vendorid=fleet['hp'].vendorid, isactive=True))
db.session.commit()
printer = Printer(vendorid=brother.vendorid, modelnumberid=None)
printer.vendor = brother
assert _printer_driver(printer, _universal()) is None
# --- the two fields the converger actually needs -----------------------------
#
# drivername is the exact string the INF declares, and it is what
# Add-PrinterDriver matches on - `name` is ours to choose and means nothing to
# Windows. vendorid attaches a universal driver (HP UPD, Xerox GPD) to a whole
# make. Neither was read from the request body, so both came back null on a
# 201, and there was no interface that could set them: the shipped converger
# had nothing to match and installed nothing, and driver-name drift could never
# be detected because the expected value was never stored.
def test_a_driver_keeps_the_inf_name_and_vendor_it_was_given(client, db,
auth_headers):
from plugins.printers.models import PrinterDriver
created = client.post('/api/printers/drivers', headers=auth_headers, json={
'name': 'HP universal',
'location': r'\\server\share\hpupd',
'drivername': 'HP Universal Printing PCL 6',
'vendorid': 1,
})
assert created.status_code == 201, created.get_json()
body = created.get_json()['data']
assert body['drivername'] == 'HP Universal Printing PCL 6'
assert body['vendorid'] == 1
stored = db.session.get(PrinterDriver, body['driverid'])
assert stored.drivername == 'HP Universal Printing PCL 6'
assert stored.vendorid == 1
def test_the_inf_name_and_vendor_can_be_changed_afterwards(client, db,
auth_headers):
created = client.post('/api/printers/drivers', headers=auth_headers, json={
'name': 'Xerox universal', 'location': r'\\server\share\xerox'})
driverid = created.get_json()['data']['driverid']
assert created.get_json()['data']['drivername'] is None
updated = client.put('/api/printers/drivers/%d' % driverid,
headers=auth_headers,
json={'drivername': 'Xerox Global Print Driver PCL6',
'vendorid': 2})
assert updated.status_code == 200, updated.get_json()
assert updated.get_json()['data']['drivername'] == \
'Xerox Global Print Driver PCL6'
assert updated.get_json()['data']['vendorid'] == 2
def test_a_blank_inf_name_clears_it_rather_than_storing_whitespace(
client, db, auth_headers):
"""An empty box means "not known", which the converger reads as "cannot
install this". A whitespace string would look set and match nothing."""
created = client.post('/api/printers/drivers', headers=auth_headers, json={
'name': 'Blank test', 'location': r'\\server\share\blank',
'drivername': ' '})
assert created.get_json()['data']['drivername'] is None