Release NixOS 23.11
[NixPkgs.git] / nixos / tests / switch-test.nix
blob5ffdf180d5e3feefb4b8e325a92ec30c976de360
1 # Test configuration switching.
3 import ./make-test-python.nix ({ lib, pkgs, ...} : let
5   # Simple service that can either be socket-activated or that will
6   # listen on port 1234 if not socket-activated.
7   # A connection to the socket causes 'hello' to be written to the client.
8   socketTest = pkgs.writeScript "socket-test.py" /* python */ ''
9     #!${pkgs.python3}/bin/python3
11     from socketserver import TCPServer, StreamRequestHandler
12     import socket
13     import os
16     class Handler(StreamRequestHandler):
17         def handle(self):
18             self.wfile.write("hello".encode("utf-8"))
21     class Server(TCPServer):
22         def __init__(self, server_address, handler_cls):
23             listenFds = os.getenv('LISTEN_FDS')
24             if listenFds is None or int(listenFds) < 1:
25                 print(f'Binding to {server_address}')
26                 TCPServer.__init__(
27                         self, server_address, handler_cls, bind_and_activate=True)
28             else:
29                 TCPServer.__init__(
30                         self, server_address, handler_cls, bind_and_activate=False)
31                 # Override socket
32                 print(f'Got activated by {os.getenv("LISTEN_FDNAMES")} '
33                       f'with {listenFds} FDs')
34                 self.socket = socket.fromfd(3, self.address_family,
35                                             self.socket_type)
38     if __name__ == "__main__":
39         server = Server(("localhost", 1234), Handler)
40         server.serve_forever()
41   '';
43 in {
44   name = "switch-test";
45   meta = with pkgs.lib.maintainers; {
46     maintainers = [ gleber das_j ];
47   };
49   nodes = {
50     machine = { pkgs, lib, ... }: {
51       environment.systemPackages = [ pkgs.socat ]; # for the socket activation stuff
52       users.mutableUsers = false;
54       # For boot/switch testing
55       system.build.installBootLoader = lib.mkForce (pkgs.writeShellScript "install-dummy-loader" ''
56         echo "installing dummy bootloader"
57         touch /tmp/bootloader-installed
58       '');
60       specialisation = rec {
61         brokenInitInterface.configuration.config.system.extraSystemBuilderCmds = ''
62           echo "systemd 0" > $out/init-interface-version
63         '';
65         modifiedSystemConf.configuration.systemd.extraConfig = ''
66           # Hello world!
67         '';
69         addedMount.configuration.virtualisation.fileSystems."/test" = {
70           device = "tmpfs";
71           fsType = "tmpfs";
72         };
74         addedMountOptsModified.configuration = {
75           imports = [ addedMount.configuration ];
76           virtualisation.fileSystems."/test".options = [ "x-test" ];
77         };
79         addedMountDevModified.configuration = {
80           imports = [ addedMountOptsModified.configuration ];
81           virtualisation.fileSystems."/test".device = lib.mkForce "ramfs";
82         };
84         storeMountModified.configuration = {
85           virtualisation.fileSystems."/".device = lib.mkForce "auto";
86         };
88         swap.configuration.swapDevices = lib.mkVMOverride [
89           { device = "/swapfile"; size = 1; }
90         ];
92         simpleService.configuration = {
93           systemd.services.test = {
94             wantedBy = [ "multi-user.target" ];
95             serviceConfig = {
96               Type = "oneshot";
97               RemainAfterExit = true;
98               ExecStart = "${pkgs.coreutils}/bin/true";
99               ExecReload = "${pkgs.coreutils}/bin/true";
100             };
101           };
102         };
104         simpleServiceSeparateActivationScript.configuration = {
105           system.activatable = false;
106           systemd.services.test = {
107             wantedBy = [ "multi-user.target" ];
108             serviceConfig = {
109               Type = "oneshot";
110               RemainAfterExit = true;
111               ExecStart = "${pkgs.coreutils}/bin/true";
112               ExecReload = "${pkgs.coreutils}/bin/true";
113             };
114           };
115         };
117         simpleServiceDifferentDescription.configuration = {
118           imports = [ simpleService.configuration ];
119           systemd.services.test.description = "Test unit";
120         };
122         simpleServiceModified.configuration = {
123           imports = [ simpleService.configuration ];
124           systemd.services.test.serviceConfig.X-Test = true;
125         };
127         simpleServiceNostop.configuration = {
128           imports = [ simpleService.configuration ];
129           systemd.services.test.stopIfChanged = false;
130         };
132         simpleServiceReload.configuration = {
133           imports = [ simpleService.configuration ];
134           systemd.services.test = {
135             reloadIfChanged = true;
136             serviceConfig.ExecReload = "${pkgs.coreutils}/bin/true";
137           };
138         };
140         simpleServiceNorestart.configuration = {
141           imports = [ simpleService.configuration ];
142           systemd.services.test.restartIfChanged = false;
143         };
145         simpleServiceFailing.configuration = {
146           imports = [ simpleServiceModified.configuration ];
147           systemd.services.test.serviceConfig.ExecStart = lib.mkForce "${pkgs.coreutils}/bin/false";
148         };
150         autorestartService.configuration = {
151           # A service that immediately goes into restarting (but without failing)
152           systemd.services.autorestart = {
153             wantedBy = [ "multi-user.target" ];
154             serviceConfig = {
155               Type = "simple";
156               Restart = "always";
157               RestartSec = "20y"; # Should be long enough
158               ExecStart = "${pkgs.coreutils}/bin/true";
159             };
160           };
161         };
163         autorestartServiceFailing.configuration = {
164           imports = [ autorestartService.configuration ];
165           systemd.services.autorestart.serviceConfig = {
166             ExecStart = lib.mkForce "${pkgs.coreutils}/bin/false";
167           };
168         };
170         simpleServiceWithExtraSection.configuration = {
171           imports = [ simpleServiceNostop.configuration ];
172           systemd.packages = [ (pkgs.writeTextFile {
173             name = "systemd-extra-section";
174             destination = "/etc/systemd/system/test.service";
175             text = ''
176               [X-Test]
177               X-Test-Value=a
178             '';
179           }) ];
180         };
182         simpleServiceWithExtraSectionOtherName.configuration = {
183           imports = [ simpleServiceNostop.configuration ];
184           systemd.packages = [ (pkgs.writeTextFile {
185             name = "systemd-extra-section";
186             destination = "/etc/systemd/system/test.service";
187             text = ''
188               [X-Test2]
189               X-Test-Value=a
190             '';
191           }) ];
192         };
194         simpleServiceWithInstallSection.configuration = {
195           imports = [ simpleServiceNostop.configuration ];
196           systemd.packages = [ (pkgs.writeTextFile {
197             name = "systemd-extra-section";
198             destination = "/etc/systemd/system/test.service";
199             text = ''
200               [Install]
201               WantedBy=multi-user.target
202             '';
203           }) ];
204         };
206         simpleServiceWithExtraKey.configuration = {
207           imports = [ simpleServiceNostop.configuration ];
208           systemd.services.test.serviceConfig."X-Test" = "test";
209         };
211         simpleServiceWithExtraKeyOtherValue.configuration = {
212           imports = [ simpleServiceNostop.configuration ];
213           systemd.services.test.serviceConfig."X-Test" = "test2";
214         };
216         simpleServiceWithExtraKeyOtherName.configuration = {
217           imports = [ simpleServiceNostop.configuration ];
218           systemd.services.test.serviceConfig."X-Test2" = "test";
219         };
221         simpleServiceReloadTrigger.configuration = {
222           imports = [ simpleServiceNostop.configuration ];
223           systemd.services.test.reloadTriggers = [ "/dev/null" ];
224         };
226         simpleServiceReloadTriggerModified.configuration = {
227           imports = [ simpleServiceNostop.configuration ];
228           systemd.services.test.reloadTriggers = [ "/dev/zero" ];
229         };
231         simpleServiceReloadTriggerModifiedAndSomethingElse.configuration = {
232           imports = [ simpleServiceNostop.configuration ];
233           systemd.services.test = {
234             reloadTriggers = [ "/dev/zero" ];
235             serviceConfig."X-Test" = "test";
236           };
237         };
239         simpleServiceReloadTriggerModifiedSomethingElse.configuration = {
240           imports = [ simpleServiceNostop.configuration ];
241           systemd.services.test.serviceConfig."X-Test" = "test";
242         };
244         unitWithBackslash.configuration = {
245           systemd.services."escaped\\x2ddash" = {
246             wantedBy = [ "multi-user.target" ];
247             serviceConfig = {
248               Type = "oneshot";
249               RemainAfterExit = true;
250               ExecStart = "${pkgs.coreutils}/bin/true";
251               ExecReload = "${pkgs.coreutils}/bin/true";
252             };
253           };
254         };
256         unitWithBackslashModified.configuration = {
257           imports = [ unitWithBackslash.configuration ];
258           systemd.services."escaped\\x2ddash".serviceConfig.X-Test = "test";
259         };
261         unitStartingWithDash.configuration = {
262           systemd.services."-" = {
263             wantedBy = [ "multi-user.target" ];
264             serviceConfig = {
265               Type = "oneshot";
266               RemainAfterExit = true;
267               ExecStart = "${pkgs.coreutils}/bin/true";
268             };
269           };
270         };
272         unitStartingWithDashModified.configuration = {
273           imports = [ unitStartingWithDash.configuration ];
274           systemd.services."-" = {
275             reloadIfChanged = true;
276             serviceConfig.ExecReload = "${pkgs.coreutils}/bin/true";
277           };
278         };
280         unitWithRequirement.configuration = {
281           systemd.services.required-service = {
282             wantedBy = [ "multi-user.target" ];
283             serviceConfig = {
284               Type = "oneshot";
285               RemainAfterExit = true;
286               ExecStart = "${pkgs.coreutils}/bin/true";
287               ExecReload = "${pkgs.coreutils}/bin/true";
288             };
289           };
290           systemd.services.test-service = {
291             wantedBy = [ "multi-user.target" ];
292             requires = [ "required-service.service" ];
293             serviceConfig = {
294               Type = "oneshot";
295               RemainAfterExit = true;
296               ExecStart = "${pkgs.coreutils}/bin/true";
297               ExecReload = "${pkgs.coreutils}/bin/true";
298             };
299           };
300         };
302         unitWithRequirementModified.configuration = {
303           imports = [ unitWithRequirement.configuration ];
304           systemd.services.required-service.serviceConfig.X-Test = "test";
305           systemd.services.test-service.reloadTriggers = [ "test" ];
306         };
308         unitWithRequirementModifiedNostart.configuration = {
309           imports = [ unitWithRequirement.configuration ];
310           systemd.services.test-service.unitConfig.RefuseManualStart = true;
311         };
313         unitWithTemplate.configuration = {
314           systemd.services."instantiated@".serviceConfig = {
315             Type = "oneshot";
316             RemainAfterExit = true;
317             ExecStart = "${pkgs.coreutils}/bin/true";
318             ExecReload = "${pkgs.coreutils}/bin/true";
319           };
320           systemd.services."instantiated@one" = {
321             wantedBy = [ "multi-user.target" ];
322             overrideStrategy = "asDropin";
323           };
324           systemd.services."instantiated@two" = {
325             wantedBy = [ "multi-user.target" ];
326             overrideStrategy = "asDropin";
327           };
328         };
330         unitWithTemplateModified.configuration = {
331           imports = [ unitWithTemplate.configuration ];
332           systemd.services."instantiated@".serviceConfig.X-Test = "test";
333         };
335         restart-and-reload-by-activation-script.configuration = {
336           systemd.services = rec {
337             simple-service = {
338               # No wantedBy so we can check if the activation script restart triggers them
339               serviceConfig = {
340                 Type = "oneshot";
341                 RemainAfterExit = true;
342                 ExecStart = "${pkgs.coreutils}/bin/true";
343                 ExecReload = "${pkgs.coreutils}/bin/true";
344               };
345             };
346             "templated-simple-service@" = simple-service;
347             "templated-simple-service@instance".overrideStrategy = "asDropin";
349             simple-restart-service = simple-service // {
350               stopIfChanged = false;
351             };
352             "templated-simple-restart-service@" = simple-restart-service;
353             "templated-simple-restart-service@instance".overrideStrategy = "asDropin";
355             simple-reload-service = simple-service // {
356               reloadIfChanged = true;
357             };
358             "templated-simple-reload-service@" = simple-reload-service;
359             "templated-simple-reload-service@instance".overrideStrategy = "asDropin";
361             no-restart-service = simple-service // {
362               restartIfChanged = false;
363             };
364             "templated-no-restart-service@" = no-restart-service;
365             "templated-no-restart-service@instance".overrideStrategy = "asDropin";
367             reload-triggers = simple-service // {
368               wantedBy = [ "multi-user.target" ];
369             };
370             "templated-reload-triggers@" = simple-service;
371             "templated-reload-triggers@instance" = {
372               overrideStrategy = "asDropin";
373               wantedBy = [ "multi-user.target" ];
374             };
376             reload-triggers-and-restart-by-as = simple-service;
377             "templated-reload-triggers-and-restart-by-as@" = reload-triggers-and-restart-by-as;
378             "templated-reload-triggers-and-restart-by-as@instance".overrideStrategy = "asDropin";
380             reload-triggers-and-restart = simple-service // {
381               stopIfChanged = false; # easier to check for this
382               wantedBy = [ "multi-user.target" ];
383             };
384             "templated-reload-triggers-and-restart@" = simple-service;
385             "templated-reload-triggers-and-restart@instance" = {
386               overrideStrategy = "asDropin";
387               stopIfChanged = false; # easier to check for this
388               wantedBy = [ "multi-user.target" ];
389             };
390           };
392           system.activationScripts.restart-and-reload-test = {
393             supportsDryActivation = true;
394             deps = [];
395             text = ''
396               if [ "$NIXOS_ACTION" = dry-activate ]; then
397                 f=/run/nixos/dry-activation-restart-list
398                 g=/run/nixos/dry-activation-reload-list
399               else
400                 f=/run/nixos/activation-restart-list
401                 g=/run/nixos/activation-reload-list
402               fi
403               cat <<EOF >> "$f"
404               simple-service.service
405               simple-restart-service.service
406               simple-reload-service.service
407               no-restart-service.service
408               reload-triggers-and-restart-by-as.service
409               templated-simple-service@instance.service
410               templated-simple-restart-service@instance.service
411               templated-simple-reload-service@instance.service
412               templated-no-restart-service@instance.service
413               templated-reload-triggers-and-restart-by-as@instance.service
414               EOF
416               cat <<EOF >> "$g"
417               reload-triggers.service
418               reload-triggers-and-restart-by-as.service
419               reload-triggers-and-restart.service
420               templated-reload-triggers@instance.service
421               templated-reload-triggers-and-restart-by-as@instance.service
422               templated-reload-triggers-and-restart@instance.service
423               EOF
424             '';
425           };
426         };
428         restart-and-reload-by-activation-script-modified.configuration = {
429           imports = [ restart-and-reload-by-activation-script.configuration ];
430           systemd.services.reload-triggers-and-restart.serviceConfig.X-Modified = "test";
431           systemd.services."templated-reload-triggers-and-restart@instance" = {
432             overrideStrategy = "asDropin";
433             serviceConfig.X-Modified = "test";
434           };
435         };
437         simple-socket.configuration = {
438           systemd.services.socket-activated = {
439             description = "A socket-activated service";
440             stopIfChanged = lib.mkDefault false;
441             serviceConfig = {
442               ExecStart = socketTest;
443               ExecReload = "${pkgs.coreutils}/bin/true";
444             };
445           };
446           systemd.sockets.socket-activated = {
447             wantedBy = [ "sockets.target" ];
448             listenStreams = [ "/run/test.sock" ];
449             socketConfig.SocketMode = lib.mkDefault "0777";
450           };
451         };
453         simple-socket-service-modified.configuration = {
454           imports = [ simple-socket.configuration ];
455           systemd.services.socket-activated.serviceConfig.X-Test = "test";
456         };
458         simple-socket-stop-if-changed.configuration = {
459           imports = [ simple-socket.configuration ];
460           systemd.services.socket-activated.stopIfChanged = true;
461         };
463         simple-socket-stop-if-changed-and-reloadtrigger.configuration = {
464           imports = [ simple-socket.configuration ];
465           systemd.services.socket-activated = {
466             stopIfChanged = true;
467             reloadTriggers = [ "test" ];
468           };
469         };
471         mount.configuration = {
472           systemd.mounts = [
473             {
474               description = "Testmount";
475               what = "tmpfs";
476               type = "tmpfs";
477               where = "/testmount";
478               options = "size=1M";
479               wantedBy = [ "local-fs.target" ];
480             }
481           ];
482         };
484         mountOptionsModified.configuration = {
485           systemd.mounts = [
486             {
487               description = "Testmount";
488               what = "tmpfs";
489               type = "tmpfs";
490               where = "/testmount";
491               options = "size=10M";
492               wantedBy = [ "local-fs.target" ];
493             }
494           ];
495         };
497         mountModified.configuration = {
498           systemd.mounts = [
499             {
500               description = "Testmount";
501               what = "ramfs";
502               type = "ramfs";
503               where = "/testmount";
504               options = "size=10M";
505               wantedBy = [ "local-fs.target" ];
506             }
507           ];
508         };
510         timer.configuration = {
511           systemd.timers.test-timer = {
512             wantedBy = [ "timers.target" ];
513             timerConfig.OnCalendar = "@1395716396"; # chosen by fair dice roll
514           };
515           systemd.services.test-timer = {
516             serviceConfig = {
517               Type = "oneshot";
518               ExecStart = "${pkgs.coreutils}/bin/true";
519             };
520           };
521         };
523         timerModified.configuration = {
524           imports = [ timer.configuration ];
525           systemd.timers.test-timer.timerConfig.OnCalendar = lib.mkForce "Fri 2012-11-23 16:00:00";
526         };
528         hybridSleepModified.configuration = {
529           systemd.targets.hybrid-sleep.unitConfig.X-Test = true;
530         };
532         target.configuration = {
533           systemd.targets.test-target.wantedBy = [ "multi-user.target" ];
534           # We use this service to figure out whether the target was modified.
535           # This is the only way because targets are filtered and therefore not
536           # printed when they are started/stopped.
537           systemd.services.test-service = {
538             bindsTo = [ "test-target.target" ];
539             serviceConfig.ExecStart = "${pkgs.coreutils}/bin/sleep infinity";
540           };
541         };
543         targetModified.configuration = {
544           imports = [ target.configuration ];
545           systemd.targets.test-target.unitConfig.X-Test = true;
546         };
548         targetModifiedStopOnReconfig.configuration = {
549           imports = [ target.configuration ];
550           systemd.targets.test-target.unitConfig.X-StopOnReconfiguration = true;
551         };
553         path.configuration = {
554           systemd.paths.test-watch = {
555             wantedBy = [ "paths.target" ];
556             pathConfig.PathExists = "/testpath";
557           };
558           systemd.services.test-watch = {
559             serviceConfig = {
560               Type = "oneshot";
561               RemainAfterExit = true;
562               ExecStart = "${pkgs.coreutils}/bin/touch /testpath-modified";
563             };
564           };
565         };
567         pathModified.configuration = {
568           imports = [ path.configuration ];
569           systemd.paths.test-watch.pathConfig.PathExists = lib.mkForce "/testpath2";
570         };
572         slice.configuration = {
573           systemd.slices.testslice.sliceConfig.MemoryMax = "1"; # don't allow memory allocation
574           systemd.services.testservice = {
575             serviceConfig = {
576               Type = "oneshot";
577               RemainAfterExit = true;
578               ExecStart = "${pkgs.coreutils}/bin/true";
579               Slice = "testslice.slice";
580             };
581           };
582         };
584         sliceModified.configuration = {
585           imports = [ slice.configuration ];
586           systemd.slices.testslice.sliceConfig.MemoryMax = lib.mkForce null;
587         };
588       };
589     };
591     other = {
592       users.mutableUsers = true;
593     };
594   };
596   testScript = { nodes, ... }: let
597     originalSystem = nodes.machine.system.build.toplevel;
598     otherSystem = nodes.other.system.build.toplevel;
599     machine = nodes.machine.system.build.toplevel;
601     # Ensures failures pass through using pipefail, otherwise failing to
602     # switch-to-configuration is hidden by the success of `tee`.
603     stderrRunner = pkgs.writeScript "stderr-runner" ''
604       #! ${pkgs.runtimeShell}
605       set -e
606       set -o pipefail
607       exec env -i "$@" | tee /dev/stderr
608     '';
610     # Returns a comma separated representation of the given list in sorted
611     # order, that matches the output format of switch-to-configuration.pl
612     sortedUnits = xs: lib.concatStringsSep ", " (builtins.sort builtins.lessThan xs);
613   in /* python */ ''
614     def switch_to_specialisation(system, name, action="test", fail=False):
615         if name == "":
616             switcher = f"{system}/bin/switch-to-configuration"
617         else:
618             switcher = f"{system}/specialisation/{name}/bin/switch-to-configuration"
619         return run_switch(switcher, action, fail)
621     # like above but stc = switcher
622     def run_switch(switcher, action="test", fail=False):
623         out = machine.fail(f"{switcher} {action} 2>&1") if fail \
624             else machine.succeed(f"{switcher} {action} 2>&1")
625         assert_lacks(out, "switch-to-configuration line")  # Perl warnings
626         return out
628     def assert_contains(haystack, needle):
629         if needle not in haystack:
630             print("The haystack that will cause the following exception is:")
631             print("---")
632             print(haystack)
633             print("---")
634             raise Exception(f"Expected string '{needle}' was not found")
636     def assert_lacks(haystack, needle):
637         if needle in haystack:
638             print("The haystack that will cause the following exception is:")
639             print("---")
640             print(haystack, end="")
641             print("---")
642             raise Exception(f"Unexpected string '{needle}' was found")
645     machine.wait_for_unit("multi-user.target")
647     machine.succeed(
648         "${stderrRunner} ${originalSystem}/bin/switch-to-configuration test"
649     )
650     # This tests whether the /etc/os-release parser works which is a fallback
651     # when /etc/NIXOS is missing. If the parser does not work, switch-to-configuration
652     # would fail.
653     machine.succeed("rm /etc/NIXOS")
654     machine.succeed(
655         "${stderrRunner} ${otherSystem}/bin/switch-to-configuration test"
656     )
659     with subtest("actions"):
660         # boot action
661         machine.fail("test -f /tmp/bootloader-installed")
662         out = switch_to_specialisation("${machine}", "simpleService", action="boot")
663         assert_contains(out, "installing dummy bootloader")
664         assert_lacks(out, "activating the configuration...")  # good indicator of a system activation
665         machine.succeed("test -f /tmp/bootloader-installed")
666         machine.succeed("rm /tmp/bootloader-installed")
668         # switch action
669         machine.fail("test -f /tmp/bootloader-installed")
670         out = switch_to_specialisation("${machine}", "", action="switch")
671         assert_contains(out, "installing dummy bootloader")
672         assert_contains(out, "activating the configuration...")  # good indicator of a system activation
673         machine.succeed("test -f /tmp/bootloader-installed")
675         # test and dry-activate actions are tested further down below
677         # invalid action fails the script
678         switch_to_specialisation("${machine}", "", action="broken-action", fail=True)
679         # no action fails the script
680         assert "Usage:" in machine.fail("${machine}/bin/switch-to-configuration 2>&1")
682     with subtest("init interface version"):
683         # Do not try to switch to an invalid init interface version
684         assert "incompatible" in switch_to_specialisation("${machine}", "brokenInitInterface", fail=True)
686     with subtest("systemd restarts"):
687         # systemd is restarted when its system.conf changes
688         out = switch_to_specialisation("${machine}", "modifiedSystemConf")
689         assert_contains(out, "restarting systemd...")
691     with subtest("continuing from an aborted switch"):
692         # An aborted switch will write into a file what it tried to start
693         # and a second switch should continue from this
694         machine.succeed("echo dbus.service > /run/nixos/start-list")
695         out = switch_to_specialisation("${machine}", "modifiedSystemConf")
696         assert_contains(out, "starting the following units: dbus.service\n")
698     with subtest("fstab mounts"):
699         switch_to_specialisation("${machine}", "")
700         # add a mountpoint
701         out = switch_to_specialisation("${machine}", "addedMount")
702         assert_lacks(out, "stopping the following units:")
703         assert_lacks(out, "NOT restarting the following changed units:")
704         assert_lacks(out, "\nrestarting the following units:")
705         assert_lacks(out, "\nstarting the following units:")
706         assert_contains(out, "the following new units were started: test.mount\n")
707         # modify the mountpoint's options
708         out = switch_to_specialisation("${machine}", "addedMountOptsModified")
709         assert_lacks(out, "stopping the following units:")
710         assert_lacks(out, "NOT restarting the following changed units:")
711         assert_contains(out, "reloading the following units: test.mount\n")
712         assert_lacks(out, "\nrestarting the following units:")
713         assert_lacks(out, "\nstarting the following units:")
714         assert_lacks(out, "the following new units were started:")
715         # modify the device
716         out = switch_to_specialisation("${machine}", "addedMountDevModified")
717         assert_lacks(out, "stopping the following units:")
718         assert_lacks(out, "NOT restarting the following changed units:")
719         assert_lacks(out, "reloading the following units:")
720         assert_contains(out, "\nrestarting the following units: test.mount\n")
721         assert_lacks(out, "\nstarting the following units:")
722         assert_lacks(out, "the following new units were started:")
723         # modify both
724         out = switch_to_specialisation("${machine}", "addedMount")
725         assert_lacks(out, "stopping the following units:")
726         assert_lacks(out, "NOT restarting the following changed units:")
727         assert_lacks(out, "reloading the following units:")
728         assert_contains(out, "\nrestarting the following units: test.mount\n")
729         assert_lacks(out, "\nstarting the following units:")
730         assert_lacks(out, "the following new units were started:")
731         # remove the mount
732         out = switch_to_specialisation("${machine}", "")
733         assert_contains(out, "stopping the following units: test.mount\n")
734         assert_lacks(out, "NOT restarting the following changed units:")
735         assert_contains(out, "reloading the following units: dbus.service\n")
736         assert_lacks(out, "\nrestarting the following units:")
737         assert_lacks(out, "\nstarting the following units:")
738         assert_lacks(out, "the following new units were started:")
739         # change something about the / mount
740         out = switch_to_specialisation("${machine}", "storeMountModified")
741         assert_lacks(out, "stopping the following units:")
742         assert_contains(out, "NOT restarting the following changed units: -.mount")
743         assert_contains(out, "reloading the following units: dbus.service\n")
744         assert_lacks(out, "\nrestarting the following units:")
745         assert_lacks(out, "\nstarting the following units:")
746         assert_lacks(out, "the following new units were started:")
748     with subtest("swaps"):
749         switch_to_specialisation("${machine}", "")
750         # add a swap
751         out = switch_to_specialisation("${machine}", "swap")
752         assert_lacks(out, "stopping the following units:")
753         assert_lacks(out, "NOT restarting the following changed units:")
754         assert_contains(out, "reloading the following units: dbus.service\n")
755         assert_lacks(out, "\nrestarting the following units:")
756         assert_lacks(out, "\nstarting the following units:")
757         assert_contains(out, "the following new units were started: swapfile.swap")
758         # remove it
759         out = switch_to_specialisation("${machine}", "")
760         assert_contains(out, "stopping swap device: /swapfile")
761         assert_lacks(out, "stopping the following units:")
762         assert_lacks(out, "NOT restarting the following changed units:")
763         assert_contains(out, "reloading the following units: dbus.service\n")
764         assert_lacks(out, "\nrestarting the following units:")
765         assert_lacks(out, "\nstarting the following units:")
766         assert_lacks(out, "the following new units were started:")
768     with subtest("services"):
769         switch_to_specialisation("${machine}", "")
770         # Nothing happens when nothing is changed
771         out = switch_to_specialisation("${machine}", "")
772         assert_lacks(out, "stopping the following units:")
773         assert_lacks(out, "NOT restarting the following changed units:")
774         assert_lacks(out, "reloading the following units:")
775         assert_lacks(out, "\nrestarting the following units:")
776         assert_lacks(out, "\nstarting the following units:")
777         assert_lacks(out, "the following new units were started:")
779         # Start a simple service
780         out = switch_to_specialisation("${machine}", "simpleService")
781         assert_lacks(out, "installing dummy bootloader")  # test does not install a bootloader
782         assert_lacks(out, "stopping the following units:")
783         assert_lacks(out, "NOT restarting the following changed units:")
784         assert_contains(out, "reloading the following units: dbus.service\n")  # huh
785         assert_lacks(out, "\nrestarting the following units:")
786         assert_lacks(out, "\nstarting the following units:")
787         assert_contains(out, "the following new units were started: test.service\n")
789         # Not changing anything doesn't do anything
790         out = switch_to_specialisation("${machine}", "simpleService")
791         assert_lacks(out, "stopping the following units:")
792         assert_lacks(out, "NOT restarting the following changed units:")
793         assert_lacks(out, "reloading the following units:")
794         assert_lacks(out, "\nrestarting the following units:")
795         assert_lacks(out, "\nstarting the following units:")
796         assert_lacks(out, "the following new units were started:")
798         # Only changing the description does nothing
799         out = switch_to_specialisation("${machine}", "simpleServiceDifferentDescription")
800         assert_lacks(out, "stopping the following units:")
801         assert_lacks(out, "NOT restarting the following changed units:")
802         assert_lacks(out, "reloading the following units:")
803         assert_lacks(out, "\nrestarting the following units:")
804         assert_lacks(out, "\nstarting the following units:")
805         assert_lacks(out, "the following new units were started:")
807         # Restart the simple service
808         out = switch_to_specialisation("${machine}", "simpleServiceModified")
809         assert_contains(out, "stopping the following units: test.service\n")
810         assert_lacks(out, "NOT restarting the following changed units:")
811         assert_lacks(out, "reloading the following units:")
812         assert_lacks(out, "\nrestarting the following units:")
813         assert_contains(out, "\nstarting the following units: test.service\n")
814         assert_lacks(out, "the following new units were started:")
816         # Restart the service with stopIfChanged=false
817         out = switch_to_specialisation("${machine}", "simpleServiceNostop")
818         assert_lacks(out, "stopping the following units:")
819         assert_lacks(out, "NOT restarting the following changed units:")
820         assert_lacks(out, "reloading the following units:")
821         assert_contains(out, "\nrestarting the following units: test.service\n")
822         assert_lacks(out, "\nstarting the following units:")
823         assert_lacks(out, "the following new units were started:")
825         # Reload the service with reloadIfChanged=true
826         out = switch_to_specialisation("${machine}", "simpleServiceReload")
827         assert_lacks(out, "stopping the following units:")
828         assert_lacks(out, "NOT restarting the following changed units:")
829         assert_contains(out, "reloading the following units: test.service\n")
830         assert_lacks(out, "\nrestarting the following units:")
831         assert_lacks(out, "\nstarting the following units:")
832         assert_lacks(out, "the following new units were started:")
834         # Nothing happens when restartIfChanged=false
835         out = switch_to_specialisation("${machine}", "simpleServiceNorestart")
836         assert_lacks(out, "stopping the following units:")
837         assert_contains(out, "NOT restarting the following changed units: test.service\n")
838         assert_lacks(out, "reloading the following units:")
839         assert_lacks(out, "\nrestarting the following units:")
840         assert_lacks(out, "\nstarting the following units:")
841         assert_lacks(out, "the following new units were started:")
843         # Dry mode shows different messages
844         out = switch_to_specialisation("${machine}", "simpleService", action="dry-activate")
845         assert_lacks(out, "stopping the following units:")
846         assert_lacks(out, "NOT restarting the following changed units:")
847         assert_lacks(out, "reloading the following units:")
848         assert_lacks(out, "\nrestarting the following units:")
849         assert_lacks(out, "\nstarting the following units:")
850         assert_lacks(out, "the following new units were started:")
851         assert_contains(out, "would start the following units: test.service\n")
853         out = switch_to_specialisation("${machine}", "", action="test")
855         # Ensure the service can be started when the activation script isn't in toplevel
856         # This is a lot like "Start a simple service", except activation-only deps could be gc-ed
857         out = run_switch("${nodes.machine.specialisation.simpleServiceSeparateActivationScript.configuration.system.build.separateActivationScript}/bin/switch-to-configuration");
858         assert_lacks(out, "installing dummy bootloader")  # test does not install a bootloader
859         assert_lacks(out, "stopping the following units:")
860         assert_lacks(out, "NOT restarting the following changed units:")
861         assert_contains(out, "reloading the following units: dbus.service\n")  # huh
862         assert_lacks(out, "\nrestarting the following units:")
863         assert_lacks(out, "\nstarting the following units:")
864         assert_contains(out, "the following new units were started: test.service\n")
865         machine.succeed("! test -e /run/current-system/activate")
866         machine.succeed("! test -e /run/current-system/dry-activate")
867         machine.succeed("! test -e /run/current-system/bin/switch-to-configuration")
869         # Ensure \ works in unit names
870         out = switch_to_specialisation("${machine}", "unitWithBackslash")
871         assert_contains(out, "stopping the following units: test.service\n")
872         assert_lacks(out, "NOT restarting the following changed units:")
873         assert_lacks(out, "reloading the following units:")
874         assert_lacks(out, "\nrestarting the following units:")
875         assert_lacks(out, "\nstarting the following units:")
876         assert_contains(out, "the following new units were started: escaped\\x2ddash.service\n")
878         out = switch_to_specialisation("${machine}", "unitWithBackslashModified")
879         assert_contains(out, "stopping the following units: escaped\\x2ddash.service\n")
880         assert_lacks(out, "NOT restarting the following changed units:")
881         assert_lacks(out, "reloading the following units:")
882         assert_lacks(out, "\nrestarting the following units:")
883         assert_contains(out, "\nstarting the following units: escaped\\x2ddash.service\n")
884         assert_lacks(out, "the following new units were started:")
886         # Ensure units can start with a dash
887         out = switch_to_specialisation("${machine}", "unitStartingWithDash")
888         assert_contains(out, "stopping the following units: escaped\\x2ddash.service\n")
889         assert_lacks(out, "NOT restarting the following changed units:")
890         assert_lacks(out, "reloading the following units:")
891         assert_lacks(out, "\nrestarting the following units:")
892         assert_lacks(out, "\nstarting the following units:")
893         assert_contains(out, "the following new units were started: -.service\n")
895         # The regression only occurs when reloading units
896         out = switch_to_specialisation("${machine}", "unitStartingWithDashModified")
897         assert_lacks(out, "stopping the following units:")
898         assert_lacks(out, "NOT restarting the following changed units:")
899         assert_contains(out, "reloading the following units: -.service")
900         assert_lacks(out, "\nrestarting the following units:")
901         assert_lacks(out, "\nstarting the following units:")
902         assert_lacks(out, "the following new units were started:")
904         # Ensure units that require changed units are properly reloaded
905         out = switch_to_specialisation("${machine}", "unitWithRequirement")
906         assert_contains(out, "stopping the following units: -.service\n")
907         assert_lacks(out, "NOT restarting the following changed units:")
908         assert_lacks(out, "reloading the following units:")
909         assert_lacks(out, "\nrestarting the following units:")
910         assert_lacks(out, "\nstarting the following units:")
911         assert_contains(out, "the following new units were started: required-service.service, test-service.service\n")
913         out = switch_to_specialisation("${machine}", "unitWithRequirementModified")
914         assert_contains(out, "stopping the following units: required-service.service\n")
915         assert_lacks(out, "NOT restarting the following changed units:")
916         assert_lacks(out, "reloading the following units:")
917         assert_lacks(out, "\nrestarting the following units:")
918         assert_contains(out, "\nstarting the following units: required-service.service, test-service.service\n")
919         assert_lacks(out, "the following new units were started:")
921         # Unless the unit asks to be not restarted
922         out = switch_to_specialisation("${machine}", "unitWithRequirementModifiedNostart")
923         assert_contains(out, "stopping the following units: required-service.service\n")
924         assert_lacks(out, "NOT restarting the following changed units:")
925         assert_lacks(out, "reloading the following units:")
926         assert_lacks(out, "\nrestarting the following units:")
927         assert_contains(out, "\nstarting the following units: required-service.service\n")
928         assert_lacks(out, "the following new units were started:")
930         # Ensure templated units are restarted when the base unit changes
931         switch_to_specialisation("${machine}", "unitWithTemplate")
932         out = switch_to_specialisation("${machine}", "unitWithTemplateModified")
933         assert_contains(out, "stopping the following units: instantiated@one.service, instantiated@two.service\n")
934         assert_lacks(out, "NOT restarting the following changed units:")
935         assert_lacks(out, "reloading the following units:")
936         assert_lacks(out, "\nrestarting the following units:")
937         assert_contains(out, "\nstarting the following units: instantiated@one.service, instantiated@two.service\n")
938         assert_lacks(out, "the following new units were started:")
940     with subtest("failing units"):
941         # Let the simple service fail
942         switch_to_specialisation("${machine}", "simpleServiceModified")
943         out = switch_to_specialisation("${machine}", "simpleServiceFailing", fail=True)
944         assert_contains(out, "stopping the following units: test.service\n")
945         assert_lacks(out, "NOT restarting the following changed units:")
946         assert_lacks(out, "reloading the following units:")
947         assert_lacks(out, "\nrestarting the following units:")
948         assert_contains(out, "\nstarting the following units: test.service\n")
949         assert_lacks(out, "the following new units were started:")
950         assert_contains(out, "warning: the following units failed: test.service\n")
951         assert_contains(out, "Main PID:")  # output of systemctl
953         # A unit that gets into autorestart without failing is not treated as failed
954         out = switch_to_specialisation("${machine}", "autorestartService")
955         assert_lacks(out, "stopping the following units:")
956         assert_lacks(out, "NOT restarting the following changed units:")
957         assert_lacks(out, "reloading the following units:")
958         assert_lacks(out, "\nrestarting the following units:")
959         assert_lacks(out, "\nstarting the following units:")
960         assert_contains(out, "the following new units were started: autorestart.service\n")
961         machine.systemctl('stop autorestart.service')  # cancel the 20y timer
963         # Switching to the same system should do nothing (especially not treat the unit as failed)
964         out = switch_to_specialisation("${machine}", "autorestartService")
965         assert_lacks(out, "stopping the following units:")
966         assert_lacks(out, "NOT restarting the following changed units:")
967         assert_lacks(out, "reloading the following units:")
968         assert_lacks(out, "\nrestarting the following units:")
969         assert_lacks(out, "\nstarting the following units:")
970         assert_contains(out, "the following new units were started: autorestart.service\n")
971         machine.systemctl('stop autorestart.service')  # cancel the 20y timer
973         # If systemd thinks the unit has failed and is in autorestart, we should show it as failed
974         out = switch_to_specialisation("${machine}", "autorestartServiceFailing", fail=True)
975         assert_lacks(out, "stopping the following units:")
976         assert_lacks(out, "NOT restarting the following changed units:")
977         assert_lacks(out, "reloading the following units:")
978         assert_lacks(out, "\nrestarting the following units:")
979         assert_lacks(out, "\nstarting the following units:")
980         assert_lacks(out, "the following new units were started:")
981         assert_contains(out, "warning: the following units failed: autorestart.service\n")
982         assert_contains(out, "Main PID:")  # output of systemctl
984     with subtest("unit file parser"):
985         # Switch to a well-known state
986         switch_to_specialisation("${machine}", "simpleServiceNostop")
988         # Add a section
989         out = switch_to_specialisation("${machine}", "simpleServiceWithExtraSection")
990         assert_lacks(out, "stopping the following units:")
991         assert_lacks(out, "NOT restarting the following changed units:")
992         assert_lacks(out, "reloading the following units:")
993         assert_contains(out, "\nrestarting the following units: test.service\n")
994         assert_lacks(out, "\nstarting the following units:")
995         assert_lacks(out, "the following new units were started:")
997         # Rename it
998         out = switch_to_specialisation("${machine}", "simpleServiceWithExtraSectionOtherName")
999         assert_lacks(out, "stopping the following units:")
1000         assert_lacks(out, "NOT restarting the following changed units:")
1001         assert_lacks(out, "reloading the following units:")
1002         assert_contains(out, "\nrestarting the following units: test.service\n")
1003         assert_lacks(out, "\nstarting the following units:")
1004         assert_lacks(out, "the following new units were started:")
1006         # Remove it
1007         out = switch_to_specialisation("${machine}", "simpleServiceNostop")
1008         assert_lacks(out, "stopping the following units:")
1009         assert_lacks(out, "NOT restarting the following changed units:")
1010         assert_lacks(out, "reloading the following units:")
1011         assert_contains(out, "\nrestarting the following units: test.service\n")
1012         assert_lacks(out, "\nstarting the following units:")
1013         assert_lacks(out, "the following new units were started:")
1015         # [Install] section is ignored
1016         out = switch_to_specialisation("${machine}", "simpleServiceWithInstallSection")
1017         assert_lacks(out, "stopping the following units:")
1018         assert_lacks(out, "NOT restarting the following changed units:")
1019         assert_lacks(out, "reloading the following units:")
1020         assert_lacks(out, "\nrestarting the following units:")
1021         assert_lacks(out, "\nstarting the following units:")
1022         assert_lacks(out, "the following new units were started:")
1024         # Add a key
1025         out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKey")
1026         assert_lacks(out, "stopping the following units:")
1027         assert_lacks(out, "NOT restarting the following changed units:")
1028         assert_lacks(out, "reloading the following units:")
1029         assert_contains(out, "\nrestarting the following units: test.service\n")
1030         assert_lacks(out, "\nstarting the following units:")
1031         assert_lacks(out, "the following new units were started:")
1033         # Change its value
1034         out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKeyOtherValue")
1035         assert_lacks(out, "stopping the following units:")
1036         assert_lacks(out, "NOT restarting the following changed units:")
1037         assert_lacks(out, "reloading the following units:")
1038         assert_contains(out, "\nrestarting the following units: test.service\n")
1039         assert_lacks(out, "\nstarting the following units:")
1040         assert_lacks(out, "the following new units were started:")
1042         # Rename it
1043         out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKeyOtherName")
1044         assert_lacks(out, "stopping the following units:")
1045         assert_lacks(out, "NOT restarting the following changed units:")
1046         assert_lacks(out, "reloading the following units:")
1047         assert_contains(out, "\nrestarting the following units: test.service\n")
1048         assert_lacks(out, "\nstarting the following units:")
1049         assert_lacks(out, "the following new units were started:")
1051         # Remove it
1052         out = switch_to_specialisation("${machine}", "simpleServiceNostop")
1053         assert_lacks(out, "stopping the following units:")
1054         assert_lacks(out, "NOT restarting the following changed units:")
1055         assert_lacks(out, "reloading the following units:")
1056         assert_contains(out, "\nrestarting the following units: test.service\n")
1057         assert_lacks(out, "\nstarting the following units:")
1058         assert_lacks(out, "the following new units were started:")
1060         # Add a reload trigger
1061         out = switch_to_specialisation("${machine}", "simpleServiceReloadTrigger")
1062         assert_lacks(out, "stopping the following units:")
1063         assert_lacks(out, "NOT restarting the following changed units:")
1064         assert_contains(out, "reloading the following units: test.service\n")
1065         assert_lacks(out, "\nrestarting the following units:")
1066         assert_lacks(out, "\nstarting the following units:")
1067         assert_lacks(out, "the following new units were started:")
1069         # Modify the reload trigger
1070         out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModified")
1071         assert_lacks(out, "stopping the following units:")
1072         assert_lacks(out, "NOT restarting the following changed units:")
1073         assert_contains(out, "reloading the following units: test.service\n")
1074         assert_lacks(out, "\nrestarting the following units:")
1075         assert_lacks(out, "\nstarting the following units:")
1076         assert_lacks(out, "the following new units were started:")
1078         # Modify the reload trigger and something else
1079         out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModifiedAndSomethingElse")
1080         assert_lacks(out, "stopping the following units:")
1081         assert_lacks(out, "NOT restarting the following changed units:")
1082         assert_lacks(out, "reloading the following units:")
1083         assert_contains(out, "\nrestarting the following units: test.service\n")
1084         assert_lacks(out, "\nstarting the following units:")
1085         assert_lacks(out, "the following new units were started:")
1087         # Remove the reload trigger
1088         out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModifiedSomethingElse")
1089         assert_lacks(out, "stopping the following units:")
1090         assert_lacks(out, "NOT restarting the following changed units:")
1091         assert_lacks(out, "reloading the following units:")
1092         assert_lacks(out, "\nrestarting the following units:")
1093         assert_lacks(out, "\nstarting the following units:")
1094         assert_lacks(out, "the following new units were started:")
1096     with subtest("restart and reload by activation script"):
1097         switch_to_specialisation("${machine}", "simpleServiceNorestart")
1098         out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script")
1099         assert_contains(out, "stopping the following units: test.service\n")
1100         assert_lacks(out, "NOT restarting the following changed units:")
1101         assert_lacks(out, "reloading the following units:")
1102         assert_lacks(out, "restarting the following units:")
1103         assert_contains(out, "\nstarting the following units: ${sortedUnits [
1104           "no-restart-service.service"
1105           "reload-triggers-and-restart-by-as.service"
1106           "simple-reload-service.service"
1107           "simple-restart-service.service"
1108           "simple-service.service"
1109           "templated-no-restart-service@instance.service"
1110           "templated-reload-triggers-and-restart-by-as@instance.service"
1111           "templated-simple-reload-service@instance.service"
1112           "templated-simple-restart-service@instance.service"
1113           "templated-simple-service@instance.service"
1114         ]}\n")
1115         assert_contains(out, "the following new units were started: ${sortedUnits [
1116           "no-restart-service.service"
1117           "reload-triggers-and-restart-by-as.service"
1118           "reload-triggers-and-restart.service"
1119           "reload-triggers.service"
1120           "simple-reload-service.service"
1121           "simple-restart-service.service"
1122           "simple-service.service"
1123           "system-templated\\\\x2dno\\\\x2drestart\\\\x2dservice.slice"
1124           "system-templated\\\\x2dreload\\\\x2dtriggers.slice"
1125           "system-templated\\\\x2dreload\\\\x2dtriggers\\\\x2dand\\\\x2drestart.slice"
1126           "system-templated\\\\x2dreload\\\\x2dtriggers\\\\x2dand\\\\x2drestart\\\\x2dby\\\\x2das.slice"
1127           "system-templated\\\\x2dsimple\\\\x2dreload\\\\x2dservice.slice"
1128           "system-templated\\\\x2dsimple\\\\x2drestart\\\\x2dservice.slice"
1129           "system-templated\\\\x2dsimple\\\\x2dservice.slice"
1130           "templated-no-restart-service@instance.service"
1131           "templated-reload-triggers-and-restart-by-as@instance.service"
1132           "templated-reload-triggers-and-restart@instance.service"
1133           "templated-reload-triggers@instance.service"
1134           "templated-simple-reload-service@instance.service"
1135           "templated-simple-restart-service@instance.service"
1136           "templated-simple-service@instance.service"
1137         ]}\n")
1138         # Switch to the same system where the example services get restarted
1139         # and reloaded by the activation script
1140         out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script")
1141         assert_lacks(out, "stopping the following units:")
1142         assert_lacks(out, "NOT restarting the following changed units:")
1143         assert_contains(out, "reloading the following units: ${sortedUnits [
1144           "reload-triggers-and-restart.service"
1145           "reload-triggers.service"
1146           "simple-reload-service.service"
1147           "templated-reload-triggers-and-restart@instance.service"
1148           "templated-reload-triggers@instance.service"
1149           "templated-simple-reload-service@instance.service"
1150         ]}\n")
1151         assert_contains(out, "restarting the following units: ${sortedUnits [
1152           "reload-triggers-and-restart-by-as.service"
1153           "simple-restart-service.service"
1154           "simple-service.service"
1155           "templated-reload-triggers-and-restart-by-as@instance.service"
1156           "templated-simple-restart-service@instance.service"
1157           "templated-simple-service@instance.service"
1158         ]}\n")
1159         assert_lacks(out, "\nstarting the following units:")
1160         assert_lacks(out, "the following new units were started:")
1161         # Switch to the same system and see if the service gets restarted when it's modified
1162         # while the fact that it's supposed to be reloaded by the activation script is ignored.
1163         out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script-modified")
1164         assert_lacks(out, "stopping the following units:")
1165         assert_lacks(out, "NOT restarting the following changed units:")
1166         assert_contains(out, "reloading the following units: ${sortedUnits [
1167           "reload-triggers.service"
1168           "simple-reload-service.service"
1169           "templated-reload-triggers@instance.service"
1170           "templated-simple-reload-service@instance.service"
1171         ]}\n")
1172         assert_contains(out, "restarting the following units: ${sortedUnits [
1173           "reload-triggers-and-restart-by-as.service"
1174           "reload-triggers-and-restart.service"
1175           "simple-restart-service.service"
1176           "simple-service.service"
1177           "templated-reload-triggers-and-restart-by-as@instance.service"
1178           "templated-reload-triggers-and-restart@instance.service"
1179           "templated-simple-restart-service@instance.service"
1180           "templated-simple-service@instance.service"
1181         ]}\n")
1182         assert_lacks(out, "\nstarting the following units:")
1183         assert_lacks(out, "the following new units were started:")
1184         # The same, but in dry mode
1185         out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script", action="dry-activate")
1186         assert_lacks(out, "would stop the following units:")
1187         assert_lacks(out, "would NOT stop the following changed units:")
1188         assert_contains(out, "would reload the following units: ${sortedUnits [
1189           "reload-triggers.service"
1190           "simple-reload-service.service"
1191           "templated-reload-triggers@instance.service"
1192           "templated-simple-reload-service@instance.service"
1193         ]}\n")
1194         assert_contains(out, "would restart the following units: ${sortedUnits [
1195           "reload-triggers-and-restart-by-as.service"
1196           "reload-triggers-and-restart.service"
1197           "simple-restart-service.service"
1198           "simple-service.service"
1199           "templated-reload-triggers-and-restart-by-as@instance.service"
1200           "templated-reload-triggers-and-restart@instance.service"
1201           "templated-simple-restart-service@instance.service"
1202           "templated-simple-service@instance.service"
1203         ]}\n")
1204         assert_lacks(out, "\nwould start the following units:")
1206     with subtest("socket-activated services"):
1207         # Socket-activated services don't get started, just the socket
1208         machine.fail("[ -S /run/test.sock ]")
1209         out = switch_to_specialisation("${machine}", "simple-socket")
1210         # assert_lacks(out, "stopping the following units:") not relevant
1211         assert_lacks(out, "NOT restarting the following changed units:")
1212         assert_lacks(out, "reloading the following units:")
1213         assert_lacks(out, "\nrestarting the following units:")
1214         assert_lacks(out, "\nstarting the following units:")
1215         assert_contains(out, "the following new units were started: socket-activated.socket\n")
1216         machine.succeed("[ -S /run/test.sock ]")
1218         # Changing a non-activated service does nothing
1219         out = switch_to_specialisation("${machine}", "simple-socket-service-modified")
1220         assert_lacks(out, "stopping the following units:")
1221         assert_lacks(out, "NOT restarting the following changed units:")
1222         assert_lacks(out, "reloading the following units:")
1223         assert_lacks(out, "\nrestarting the following units:")
1224         assert_lacks(out, "\nstarting the following units:")
1225         assert_lacks(out, "the following new units were started:")
1226         machine.succeed("[ -S /run/test.sock ]")
1227         # The unit is properly activated when the socket is accessed
1228         if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
1229             raise Exception("Socket was not properly activated")  # idk how that would happen tbh
1231         # Changing an activated service with stopIfChanged=false restarts the service
1232         out = switch_to_specialisation("${machine}", "simple-socket")
1233         assert_lacks(out, "stopping the following units:")
1234         assert_lacks(out, "NOT restarting the following changed units:")
1235         assert_lacks(out, "reloading the following units:")
1236         assert_contains(out, "\nrestarting the following units: socket-activated.service\n")
1237         assert_lacks(out, "\nstarting the following units:")
1238         assert_lacks(out, "the following new units were started:")
1239         machine.succeed("[ -S /run/test.sock ]")
1240         # Socket-activation of the unit still works
1241         if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
1242             raise Exception("Socket was not properly activated after the service was restarted")
1244         # Changing an activated service with stopIfChanged=true stops the service and
1245         # socket and starts the socket
1246         out = switch_to_specialisation("${machine}", "simple-socket-stop-if-changed")
1247         assert_contains(out, "stopping the following units: socket-activated.service, socket-activated.socket\n")
1248         assert_lacks(out, "NOT restarting the following changed units:")
1249         assert_lacks(out, "reloading the following units:")
1250         assert_lacks(out, "\nrestarting the following units:")
1251         assert_contains(out, "\nstarting the following units: socket-activated.socket\n")
1252         assert_lacks(out, "the following new units were started:")
1253         machine.succeed("[ -S /run/test.sock ]")
1254         # Socket-activation of the unit still works
1255         if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
1256             raise Exception("Socket was not properly activated after the service was restarted")
1258         # Changing a reload trigger of a socket-activated unit only reloads it
1259         out = switch_to_specialisation("${machine}", "simple-socket-stop-if-changed-and-reloadtrigger")
1260         assert_lacks(out, "stopping the following units:")
1261         assert_lacks(out, "NOT restarting the following changed units:")
1262         assert_contains(out, "reloading the following units: socket-activated.service\n")
1263         assert_lacks(out, "\nrestarting the following units:")
1264         assert_lacks(out, "\nstarting the following units: socket-activated.socket")
1265         assert_lacks(out, "the following new units were started:")
1266         machine.succeed("[ -S /run/test.sock ]")
1267         # Socket-activation of the unit still works
1268         if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
1269             raise Exception("Socket was not properly activated after the service was restarted")
1271     with subtest("mounts"):
1272         switch_to_specialisation("${machine}", "mount")
1273         out = machine.succeed("mount | grep 'on /testmount'")
1274         assert_contains(out, "size=1024k")
1275         # Changing options reloads the unit
1276         out = switch_to_specialisation("${machine}", "mountOptionsModified")
1277         assert_lacks(out, "stopping the following units:")
1278         assert_lacks(out, "NOT restarting the following changed units:")
1279         assert_contains(out, "reloading the following units: testmount.mount\n")
1280         assert_lacks(out, "\nrestarting the following units:")
1281         assert_lacks(out, "\nstarting the following units:")
1282         assert_lacks(out, "the following new units were started:")
1283         # It changed
1284         out = machine.succeed("mount | grep 'on /testmount'")
1285         assert_contains(out, "size=10240k")
1286         # Changing anything but `Options=` restarts the unit
1287         out = switch_to_specialisation("${machine}", "mountModified")
1288         assert_lacks(out, "stopping the following units:")
1289         assert_lacks(out, "NOT restarting the following changed units:")
1290         assert_lacks(out, "reloading the following units:")
1291         assert_contains(out, "\nrestarting the following units: testmount.mount\n")
1292         assert_lacks(out, "\nstarting the following units:")
1293         assert_lacks(out, "the following new units were started:")
1294         # It changed
1295         out = machine.succeed("mount | grep 'on /testmount'")
1296         assert_contains(out, "ramfs")
1298     with subtest("timers"):
1299         switch_to_specialisation("${machine}", "timer")
1300         out = machine.succeed("systemctl show test-timer.timer")
1301         assert_contains(out, "OnCalendar=2014-03-25 02:59:56 UTC")
1302         out = switch_to_specialisation("${machine}", "timerModified")
1303         assert_lacks(out, "stopping the following units:")
1304         assert_lacks(out, "NOT restarting the following units:")
1305         assert_lacks(out, "reloading the following units:")
1306         assert_contains(out, "\nrestarting the following units: test-timer.timer\n")
1307         assert_lacks(out, "\nstarting the following units:")
1308         assert_lacks(out, "the following new units were started:")
1309         # It changed
1310         out = machine.succeed("systemctl show test-timer.timer")
1311         assert_contains(out, "OnCalendar=Fri 2012-11-23 16:00:00")
1313     with subtest("targets"):
1314         # Modifying some special targets like hybrid-sleep.target does nothing
1315         out = switch_to_specialisation("${machine}", "hybridSleepModified")
1316         assert_contains(out, "stopping the following units: test-timer.timer\n")
1317         assert_lacks(out, "NOT restarting the following changed units:")
1318         assert_lacks(out, "reloading the following units:")
1319         assert_lacks(out, "\nrestarting the following units:")
1320         assert_lacks(out, "\nstarting the following units:")
1321         assert_lacks(out, "the following new units were started:")
1323         # Adding a new target starts it
1324         out = switch_to_specialisation("${machine}", "target")
1325         assert_lacks(out, "stopping the following units:")
1326         assert_lacks(out, "NOT restarting the following changed units:")
1327         assert_lacks(out, "reloading the following units:")
1328         assert_lacks(out, "\nrestarting the following units:")
1329         assert_lacks(out, "\nstarting the following units:")
1330         assert_contains(out, "the following new units were started: test-target.target\n")
1332         # Changing a target doesn't print anything because the unit is filtered
1333         machine.systemctl("start test-service.service")
1334         out = switch_to_specialisation("${machine}", "targetModified")
1335         assert_lacks(out, "stopping the following units:")
1336         assert_lacks(out, "NOT restarting the following changed units:")
1337         assert_lacks(out, "reloading the following units:")
1338         assert_lacks(out, "\nrestarting the following units:")
1339         assert_lacks(out, "\nstarting the following units:")
1340         assert_lacks(out, "the following new units were started:")
1341         machine.succeed("systemctl is-active test-service.service")  # target was not restarted
1343         # With X-StopOnReconfiguration, the target gets stopped and started
1344         out = switch_to_specialisation("${machine}", "targetModifiedStopOnReconfig")
1345         assert_lacks(out, "stopping the following units:")
1346         assert_lacks(out, "NOT restarting the following changed units:")
1347         assert_lacks(out, "reloading the following units:")
1348         assert_lacks(out, "\nrestarting the following units:")
1349         assert_lacks(out, "\nstarting the following units:")
1350         assert_lacks(out, "the following new units were started:")
1351         machine.fail("systemctl is-active test-service.servce")  # target was restarted
1353         # Remove the target by switching to the old specialisation
1354         out = switch_to_specialisation("${machine}", "timerModified")
1355         assert_contains(out, "stopping the following units: test-target.target\n")
1356         assert_lacks(out, "NOT restarting the following changed units:")
1357         assert_lacks(out, "reloading the following units:")
1358         assert_lacks(out, "\nrestarting the following units:")
1359         assert_lacks(out, "\nstarting the following units:")
1360         assert_contains(out, "the following new units were started: test-timer.timer\n")
1362     with subtest("paths"):
1363         out = switch_to_specialisation("${machine}", "path")
1364         assert_contains(out, "stopping the following units: test-timer.timer\n")
1365         assert_lacks(out, "NOT restarting the following changed units:")
1366         assert_lacks(out, "reloading the following units:")
1367         assert_lacks(out, "\nrestarting the following units:")
1368         assert_lacks(out, "\nstarting the following units:")
1369         assert_contains(out, "the following new units were started: test-watch.path\n")
1370         machine.fail("test -f /testpath-modified")
1372         # touch the file, unit should be triggered
1373         machine.succeed("touch /testpath")
1374         machine.wait_until_succeeds("test -f /testpath-modified")
1375         machine.succeed("rm /testpath /testpath-modified")
1376         machine.systemctl("stop test-watch.service")
1377         switch_to_specialisation("${machine}", "pathModified")
1378         machine.succeed("touch /testpath")
1379         machine.fail("test -f /testpath-modified")
1380         machine.succeed("touch /testpath2")
1381         machine.wait_until_succeeds("test -f /testpath-modified")
1383     # This test ensures that changes to slice configuration get applied.
1384     # We test this by having a slice that allows no memory allocation at
1385     # all and starting a service within it. If the service crashes, the slice
1386     # is applied and if we modify the slice to allow memory allocation, the
1387     # service should successfully start.
1388     with subtest("slices"):
1389         machine.succeed("echo 0 > /proc/sys/vm/panic_on_oom")  # allow OOMing
1390         out = switch_to_specialisation("${machine}", "slice")
1391         # assert_lacks(out, "stopping the following units:") not relevant
1392         assert_lacks(out, "NOT restarting the following changed units:")
1393         assert_lacks(out, "reloading the following units:")
1394         assert_lacks(out, "\nrestarting the following units:")
1395         assert_lacks(out, "\nstarting the following units:")
1396         assert_lacks(out, "the following new units were started:")
1397         machine.fail("systemctl start testservice.service")
1399         out = switch_to_specialisation("${machine}", "sliceModified")
1400         assert_lacks(out, "stopping the following units:")
1401         assert_lacks(out, "NOT restarting the following changed units:")
1402         assert_lacks(out, "reloading the following units:")
1403         assert_lacks(out, "\nrestarting the following units:")
1404         assert_lacks(out, "\nstarting the following units:")
1405         assert_lacks(out, "the following new units were started:")
1406         machine.succeed("systemctl start testservice.service")
1407         machine.succeed("echo 1 > /proc/sys/vm/panic_on_oom")  # disallow OOMing
1408   '';