| 
									
										
										
										
											2013-09-26 21:00:30 +02:00
										 |  |  | # Test printing via CUPS. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-06 11:29:23 +01:00
										 |  |  | import ./make-test-python.nix ({pkgs, ... }: | 
					
						
							| 
									
										
										
										
											2019-08-05 20:24:18 +02:00
										 |  |  | let | 
					
						
							|  |  |  |   printingServer = startWhenNeeded: { | 
					
						
							|  |  |  |     services.printing.enable = true; | 
					
						
							|  |  |  |     services.printing.startWhenNeeded = startWhenNeeded; | 
					
						
							|  |  |  |     services.printing.listenAddresses = [ "*:631" ]; | 
					
						
							|  |  |  |     services.printing.defaultShared = true; | 
					
						
							| 
									
										
										
										
											2020-02-06 11:29:23 +01:00
										 |  |  |     services.printing.extraConf = ''
 | 
					
						
							|  |  |  |       <Location /> | 
					
						
							|  |  |  |         Order allow,deny | 
					
						
							|  |  |  |         Allow from all | 
					
						
							|  |  |  |       </Location> | 
					
						
							|  |  |  |     '';
 | 
					
						
							| 
									
										
										
										
											2019-08-05 20:24:18 +02:00
										 |  |  |     networking.firewall.allowedTCPPorts = [ 631 ]; | 
					
						
							|  |  |  |     # 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"; | 
					
						
							|  |  |  |     }]; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   printingClient = startWhenNeeded: { | 
					
						
							|  |  |  |     services.printing.enable = true; | 
					
						
							|  |  |  |     services.printing.startWhenNeeded = startWhenNeeded; | 
					
						
							|  |  |  |     # Add printer to the client as well, via IPP. | 
					
						
							|  |  |  |     hardware.printers.ensurePrinters = [{ | 
					
						
							|  |  |  |       name = "DeskjetRemote"; | 
					
						
							|  |  |  |       deviceUri = "ipp://${if startWhenNeeded then "socketActivatedServer" else "serviceServer"}/printers/DeskjetLocal"; | 
					
						
							|  |  |  |       model = "drv:///sample.drv/deskjet.ppd"; | 
					
						
							|  |  |  |     }]; | 
					
						
							|  |  |  |     hardware.printers.ensureDefaultPrinter = "DeskjetRemote"; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-06 11:29:23 +01:00
										 |  |  | in { | 
					
						
							| 
									
										
										
										
											2014-06-28 16:04:49 +02:00
										 |  |  |   name = "printing"; | 
					
						
							| 
									
										
										
										
											2021-01-10 20:08:30 +01:00
										 |  |  |   meta = with pkgs.lib.maintainers; { | 
					
						
							| 
									
										
										
										
											2019-08-14 11:44:30 -04:00
										 |  |  |     maintainers = [ domenkozar eelco matthewbauer ]; | 
					
						
							| 
									
										
										
										
											2015-07-12 12:09:40 +02:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2013-09-26 21:00:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   nodes = { | 
					
						
							| 
									
										
										
										
											2019-08-05 20:24:18 +02:00
										 |  |  |     socketActivatedServer = { ... }: (printingServer true); | 
					
						
							|  |  |  |     serviceServer = { ... }: (printingServer false); | 
					
						
							| 
									
										
										
										
											2013-09-26 21:00:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-05 20:24:18 +02:00
										 |  |  |     socketActivatedClient = { ... }: (printingClient true); | 
					
						
							|  |  |  |     serviceClient = { ... }: (printingClient false); | 
					
						
							| 
									
										
										
										
											2013-09-26 21:00:30 +02:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-06 11:29:23 +01:00
										 |  |  |   testScript = ''
 | 
					
						
							|  |  |  |     import os | 
					
						
							|  |  |  |     import re | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     start_all() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     with subtest("Make sure that cups is up on both sides"): | 
					
						
							|  |  |  |         serviceServer.wait_for_unit("cups.service") | 
					
						
							|  |  |  |         serviceClient.wait_for_unit("cups.service") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     with subtest( | 
					
						
							|  |  |  |         "Wait until cups is fully initialized and ensure-printers has " | 
					
						
							|  |  |  |         "executed with 10s delay" | 
					
						
							|  |  |  |     ): | 
					
						
							|  |  |  |         serviceClient.sleep(20) | 
					
						
							|  |  |  |         socketActivatedClient.wait_until_succeeds( | 
					
						
							|  |  |  |             "systemctl status ensure-printers | grep -q -E 'code=exited, status=0/SUCCESS'" | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_printing(client, server): | 
					
						
							|  |  |  |         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"): | 
					
						
							|  |  |  |             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}'" | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # 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}'") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # 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'") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 retry(lambda _: "no entries" in server.succeed("lpq -a")) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # 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/*") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     test_printing(serviceClient, serviceServer) | 
					
						
							|  |  |  |     test_printing(socketActivatedClient, socketActivatedServer) | 
					
						
							| 
									
										
										
										
											2019-08-05 20:24:18 +02:00
										 |  |  |   '';
 | 
					
						
							| 
									
										
										
										
											2014-04-14 14:02:44 +02:00
										 |  |  | }) |