1 # Test printing via CUPS.
3 import ./make-test-python.nix (
5 , socket ? true # whether to use socket activation
11 meta = with pkgs.lib.maintainers; {
12 maintainers = [ domenkozar matthewbauer ];
15 nodes.server = { ... }: {
19 startWhenNeeded = socket;
20 listenAddresses = [ "*:631" ];
30 # Add a HP Deskjet printer connected via USB to the server.
31 hardware.printers.ensurePrinters = [{
32 name = "DeskjetLocal";
33 deviceUri = "usb://foobar/printers/foobar";
34 model = "drv:///sample.drv/deskjet.ppd";
38 nodes.client = { ... }: {
39 services.printing.enable = true;
40 services.printing.startWhenNeeded = socket;
41 # Add printer to the client as well, via IPP.
42 hardware.printers.ensurePrinters = [{
43 name = "DeskjetRemote";
44 deviceUri = "ipp://server/printers/DeskjetLocal";
45 model = "drv:///sample.drv/deskjet.ppd";
47 hardware.printers.ensureDefaultPrinter = "DeskjetRemote";
56 with subtest("Make sure that cups is up on both sides and printers are set up"):
57 server.wait_for_unit("cups.${if socket then "socket" else "service"}")
58 client.wait_for_unit("cups.${if socket then "socket" else "service"}")
60 assert "scheduler is running" in client.succeed("lpstat -r")
62 with subtest("UNIX socket is used for connections"):
63 assert "/var/run/cups/cups.sock" in client.succeed("lpstat -H")
65 with subtest("HTTP server is available too"):
66 client.succeed("curl --fail http://localhost:631/")
67 client.succeed(f"curl --fail http://{server.name}:631/")
68 server.fail(f"curl --fail --connect-timeout 2 http://{client.name}:631/")
70 with subtest("LP status checks"):
71 assert "DeskjetRemote accepting requests" in client.succeed("lpstat -a")
72 assert "DeskjetLocal accepting requests" in client.succeed(
73 f"lpstat -h {server.name}:631 -a"
75 client.succeed("cupsdisable DeskjetRemote")
76 out = client.succeed("lpq")
79 "DeskjetRemote is not ready.*no entries",
80 client.succeed("lpq"),
83 client.succeed("cupsenable DeskjetRemote")
85 "DeskjetRemote is ready.*no entries", client.succeed("lpq"), flags=re.DOTALL
88 # Test printing various file types.
90 "${pkgs.groff.doc}/share/doc/*/examples/mom/penguin.pdf",
91 "${pkgs.groff.doc}/share/doc/*/meref.ps",
92 "${pkgs.cups.out}/share/doc/cups/images/cups.png",
93 "${pkgs.pcre.doc}/share/doc/pcre/pcre.txt",
95 file_name = os.path.basename(file)
96 with subtest(f"print {file_name}"):
97 # Print the file on the client.
98 print(client.succeed("lpq"))
99 client.succeed(f"lp {file}")
100 client.wait_until_succeeds(
101 f"lpq; lpq | grep -q -E 'active.*root.*{file_name}'"
104 # Ensure that a raw PCL file appeared in the server's queue
105 # (showing that the right filters have been applied). Of
106 # course, since there is no actual USB printer attached, the
107 # file will stay in the queue forever.
108 server.wait_for_file("/var/spool/cups/d*-001")
109 server.wait_until_succeeds(f"lpq -a | grep -q -E '{file_name}'")
111 # Delete the job on the client. It should disappear on the
113 client.succeed("lprm")
114 client.wait_until_succeeds("lpq -a | grep -q -E 'no entries'")
116 retry(lambda _: "no entries" in server.succeed("lpq -a"))
118 # The queue is empty already, so this should be safe.
119 # Otherwise, pairs of "c*"-"d*-001" files might persist.
120 server.execute("rm /var/spool/cups/*")