nixpkgs/nixos/tests/printing.nix

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

129 lines
4.2 KiB
Nix
Raw Normal View History

2013-09-26 19:00:30 +00:00
# Test printing via CUPS.
import ./make-test-python.nix (
{ pkgs
, socket ? true # whether to use socket activation
, listenTcp ? true # whether to open port 631 on client
, ...
}:
2024-10-27 09:47:31 +00:00
let
inherit (pkgs) lib;
in
{
name = "printing";
2024-10-27 09:47:31 +00:00
meta = with lib.maintainers; {
maintainers = [ domenkozar matthewbauer ];
};
nodes.server = { ... }: {
services.printing = {
enable = true;
stateless = true;
startWhenNeeded = socket;
listenAddresses = [ "*:631" ];
defaultShared = true;
openFirewall = true;
extraConf = ''
<Location />
Order allow,deny
Allow from all
</Location>
'';
};
# Add a HP Deskjet printer connected via USB to the server.
hardware.printers.ensurePrinters = [{
name = "DeskjetLocal";
deviceUri = "usb://foobar/printers/foobar";
model = "drv:///sample.drv/deskjet.ppd";
}];
};
nodes.client = { lib, ... }: {
services.printing.enable = true;
services.printing.startWhenNeeded = socket;
services.printing.listenAddresses = lib.mkIf (!listenTcp) [];
# Add printer to the client as well, via IPP.
hardware.printers.ensurePrinters = [{
name = "DeskjetRemote";
deviceUri = "ipp://server/printers/DeskjetLocal";
model = "drv:///sample.drv/deskjet.ppd";
}];
hardware.printers.ensureDefaultPrinter = "DeskjetRemote";
};
2020-02-06 10:29:23 +00:00
testScript = ''
import os
import re
start_all()
with subtest("Make sure that cups is up on both sides and printers are set up"):
nixos/tests/printing: fix race of lpstat and ensure-printers There is a nasty race condition in the cups tests. To understand what is going on, one must first note that printers are installed in the vms with ensure-printers.service, which is started as part of multi-user.target. ensure-printers.service in turn triggers a start of cups.service as it needs to connect to the local cups daemon. This is what happens when the test runs: 1 the test waits for cups.socket or cups.service to start up (subtest "Make sure that cups is up on both sides...") 2 after cups.service started (it starts even in the "socket" case, triggered by ensure-printers.service), ensure-printers.service is started 3 the test tries to connect to the cups daemons via curl (subtest "HTTP server is available too") 4 the test verifies the required printers are installed ("lpstat -a" called by subtest "LP status checks") Usually, 3 needs some time, so ensure-printers.service already installed all printers that are required by 4. But if 3 is too fast, or if ensure-printers.service is too slow, 4 fails to find the printers it is looking for. One can provoke the problem by adding > systemd.services.ensure-printers.serviceConfig.ExecStartPre = "/run/current-system/sw/bin/sleep 10"; to the `nodes.client` configuration. The commit at hand fixes the problem by changing 1: Instead of waiting for cups, it now waits for ensure-printers.service (which in turn waits for cups.service and cups.socket). This is also in accordance with the subtest description in the code that promises to "Make sure that cups is up [...] and printers are set up".
2024-08-29 13:12:49 +00:00
server.wait_for_unit("ensure-printers.service")
client.wait_for_unit("ensure-printers.service")
assert "scheduler is running" in client.succeed("lpstat -r")
with subtest("UNIX socket is used for connections"):
assert "/var/run/cups/cups.sock" in client.succeed("lpstat -H")
with subtest("HTTP server is available too"):
${lib.optionalString listenTcp ''client.succeed("curl --fail http://localhost:631/")''}
client.succeed(f"curl --fail http://{server.name}:631/")
server.fail(f"curl --fail --connect-timeout 2 http://{client.name}:631/")
with subtest("LP status checks"):
assert "DeskjetRemote accepting requests" in client.succeed("lpstat -a")
assert "DeskjetLocal accepting requests" in client.succeed(
f"lpstat -h {server.name}:631 -a"
)
client.succeed("cupsdisable DeskjetRemote")
out = client.succeed("lpq")
print(out)
assert re.search(
"DeskjetRemote is not ready.*no entries",
client.succeed("lpq"),
flags=re.DOTALL,
)
client.succeed("cupsenable DeskjetRemote")
assert re.match(
"DeskjetRemote is ready.*no entries", client.succeed("lpq"), flags=re.DOTALL
)
# Test printing various file types.
for file in [
"${pkgs.groff.doc}/share/doc/*/examples/mom/penguin.pdf",
"${pkgs.groff.doc}/share/doc/*/meref.ps",
"${pkgs.cups.out}/share/doc/cups/images/cups.png",
"${pkgs.pcre.doc}/share/doc/pcre/pcre.txt",
]:
file_name = os.path.basename(file)
with subtest(f"print {file_name}"):
# Print the file on the client.
print(client.succeed("lpq"))
client.succeed(f"lp {file}")
client.wait_until_succeeds(
f"lpq; lpq | grep -q -E 'active.*root.*{file_name}'"
)
2020-02-06 10:29:23 +00:00
# Ensure that a raw PCL file appeared in the server's queue
# (showing that the right filters have been applied). Of
# course, since there is no actual USB printer attached, the
# file will stay in the queue forever.
server.wait_for_file("/var/spool/cups/d*-001")
server.wait_until_succeeds(f"lpq -a | grep -q -E '{file_name}'")
2020-02-06 10:29:23 +00:00
# Delete the job on the client. It should disappear on the
# server as well.
client.succeed("lprm")
client.wait_until_succeeds("lpq -a | grep -q -E 'no entries'")
2020-02-06 10:29:23 +00:00
retry(lambda _: "no entries" in server.succeed("lpq -a"))
2020-02-06 10:29:23 +00:00
# The queue is empty already, so this should be safe.
# Otherwise, pairs of "c*"-"d*-001" files might persist.
server.execute("rm /var/spool/cups/*")
'';
})