Faithful print and device emulation
A printer in an enterprise is really two things wearing one label: a print server that accepts and spools jobs, and a physical device that has toner, paper, status lights, and an SNMP agent. The lab emulates both, separately, because the thing under test usually touches both.
flowchart TB
app["Application under test<br/>(e.g. the fax broker)"]
subgraph server["Print server layer · print-server"]
cups["CUPS · spooler RPCs · IPP :631<br/>SMB \\print1\\queue · Point-and-Print"]
end
subgraph device["Device layer · sidecars"]
snmp["print-snmp<br/>Printer-MIB status + supplies"]
ipp["print-ipp<br/>IPP Everywhere"]
end
app -->|"submit jobs (SMB/IPP)"| cups
app -->|"poll status (SNMP)"| snmp
fault["make print-fault"] -->|"queue state"| cups
fault -->|"device OIDs"| snmp
The print server layer
Section titled “The print server layer”print-server is a Samba member server running CUPS. It speaks the real
Windows-facing wire protocols a print server speaks:
- SMB print spooling (
\\print1\<queue>) - the
EnumPrinters/OpenPrinterspooler RPCs - Point-and-Print driver download from
[print$] - IPP, via CUPS on port 631
It is not a substitute for the Windows management surface (PowerShell
*-Printer* cmdlets, WMI Win32_Printer), because those ride WinRM/WMI, which
Samba does not speak. Within the wire-protocol scope, though, it behaves like the
real thing: a job submitted over SMB travels smbd to spoolss to CUPS to cups-pdf
and lands as a PDF you can inspect.
Realism that matters for testing
Section titled “Realism that matters for testing”The real GH01-PRINT01 has 77 queues, so the emulator builds a full roster from
a bind-mounted queues.txt. Replacing that file with a production lpstat -v
dump and restarting is all it takes to mirror a real fleet. Queues can carry
per-queue ACLs (a CUPS AllowUser @group policy against a winbind-resolved AD
group), and the enforcement is real: a non-member’s job is dropped by CUPS even
though the SMB upload succeeds. And each queue self-publishes to AD as a
printQueue object so it is discoverable in the directory, the one AD-native
trick that plain SMB sharing does not cover.
The device layer
Section titled “The device layer”A print server speaks SMB and IPP; it does not have toner. Real printer hardware exposes SNMP status and supplies and an IPP endpoint of its own. Two sidecars emulate that device side:
print-snmp(snmpsim) serves a Printer-MIB per simulated printer, one per SNMPv2c community equal to the lowercased queue name. It models a handful of representative printers rather than all 77, though the same renderer could generate all of them.print-ipp(ippeveprinter) runs a few IPP Everywhere reference printers, capturing jobs. It needs a local Avahi because ippeveprinter hard-requires DNS-SD. For all 77 queues, CUPS onprint-server:631already serves real IPP; this sidecar is the driverless IPP-Everywhere reference.
Why split them
Section titled “Why split them”Because failures are where the interesting testing lives, and failures happen at the device, not the server. A printer runs out of toner, jams, or goes offline, and the device reports that over SNMP while the server may or may not be able to spool to it. The lab’s fault injection flips both layers at once: it writes an SNMP state the device reports and sets the CUPS queue state, so a single command reproduces “the device says low toner and the queue is refusing jobs,” exactly the situation that breaks naive printer code.
Keeping the two layers as separate services is what makes that possible. A monolith pretending to be both could only fake one side coherently.
The takeaway
Section titled “The takeaway”Emulate the protocols, not the appearance. The print server reproduces the wire behaviour an application drives; the device sidecars reproduce the status and fault behaviour an application has to react to. Together they let you test the happy path and, more importantly, the unhappy ones.