Resolve a driver by vendor, and converge a bay's printers from ShopDB
Two rows now cover 41 of 44 printers. printerdrivers could only bind a driver to ONE modelnumberid, so the HP and Xerox universal drivers - which between them cover almost the whole floor - would have needed 21 near-duplicate rows pointing at the same package. That is a table nobody keeps true, and it is why 42 of 44 printers resolved no driver at all. printerdrivers gains vendorid, and resolution runs most-specific-first: the printer's model, then its vendor, then the pre-vendorid convention of matching the vendor word in the driver's name so a site that populated the table before the column existed does not silently lose every driver on upgrade. A row that names a vendor is never matched by its text, because a mis-set vendor resolving to the wrong package is worse than resolving to none. Six rows now resolve 44 of 44 printers at the reference site, and the DesignJet correctly takes its own driver over the HP universal one. Set-ShopdbPrinters.ps1 is the client half: ask for-host, create the queues that are missing, record the desired default. It NEVER removes a queue - a bad minute from the API must not take printers away from a working bay - and it never fetches a driver, because downloading 48 MB while somebody waits to print is the wrong moment. The common scope stages those. Apply-ShopdbDefaultPrinter.ps1 applies the default in the USER's context, which is the only context that can: SYSTEM cannot set a per-user default for somebody else. It also turns off "Let Windows manage my default printer", without which Windows silently overwrites the choice the next time anyone prints elsewhere - a fix that undoes itself within a day. VALIDATED ON WINDOWS 11 AGAINST A LIVE SHOPDB, not only by tests. Printers were assigned to a MACHINE; a PC controlling it, holding no rows of its own, created both queues bound to the right universal drivers, recorded the default and set it, and a second run changed nothing. The first attempt failed with "Relationship types are not seeded - run: flask seed reference-data", which is the deployment trap the plan predicted, caught by an explicit error rather than silently resolving nothing.
This commit is contained in:
120
tests/test_plugins/test_printer_driver_resolution.py
Normal file
120
tests/test_plugins/test_printer_driver_resolution.py
Normal file
@@ -0,0 +1,120 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user