Merge pull request #305845 from abathur/resholve_0.10.5
[NixPkgs.git] / nixos / tests / switch-test.nix
blob4a7bcd5a8226450b313fe51d01e9cd3a34f3f324
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);
614     dbusService = {
615       "dbus" = "dbus.service";
616       "broker" = "dbus-broker.service";
617     }.${nodes.machine.services.dbus.implementation};
618   in /* python */ ''
619     def switch_to_specialisation(system, name, action="test", fail=False):
620         if name == "":
621             switcher = f"{system}/bin/switch-to-configuration"
622         else:
623             switcher = f"{system}/specialisation/{name}/bin/switch-to-configuration"
624         return run_switch(switcher, action, fail)
626     # like above but stc = switcher
627     def run_switch(switcher, action="test", fail=False):
628         out = machine.fail(f"{switcher} {action} 2>&1") if fail \
629             else machine.succeed(f"{switcher} {action} 2>&1")
630         assert_lacks(out, "switch-to-configuration line")  # Perl warnings
631         return out
633     def assert_contains(haystack, needle):
634         if needle not in haystack:
635             print("The haystack that will cause the following exception is:")
636             print("---")
637             print(haystack)
638             print("---")
639             raise Exception(f"Expected string '{needle}' was not found")
641     def assert_lacks(haystack, needle):
642         if needle in haystack:
643             print("The haystack that will cause the following exception is:")
644             print("---")
645             print(haystack, end="")
646             print("---")
647             raise Exception(f"Unexpected string '{needle}' was found")
650     machine.wait_for_unit("multi-user.target")
652     machine.succeed(
653         "${stderrRunner} ${originalSystem}/bin/switch-to-configuration test"
654     )
655     # This tests whether the /etc/os-release parser works which is a fallback
656     # when /etc/NIXOS is missing. If the parser does not work, switch-to-configuration
657     # would fail.
658     machine.succeed("rm /etc/NIXOS")
659     machine.succeed(
660         "${stderrRunner} ${otherSystem}/bin/switch-to-configuration test"
661     )
664     with subtest("actions"):
665         # boot action
666         machine.fail("test -f /tmp/bootloader-installed")
667         out = switch_to_specialisation("${machine}", "simpleService", action="boot")
668         assert_contains(out, "installing dummy bootloader")
669         assert_lacks(out, "activating the configuration...")  # good indicator of a system activation
670         machine.succeed("test -f /tmp/bootloader-installed")
671         machine.succeed("rm /tmp/bootloader-installed")
673         # switch action
674         machine.fail("test -f /tmp/bootloader-installed")
675         out = switch_to_specialisation("${machine}", "", action="switch")
676         assert_contains(out, "installing dummy bootloader")
677         assert_contains(out, "activating the configuration...")  # good indicator of a system activation
678         machine.succeed("test -f /tmp/bootloader-installed")
680         # test and dry-activate actions are tested further down below
682         # invalid action fails the script
683         switch_to_specialisation("${machine}", "", action="broken-action", fail=True)
684         # no action fails the script
685         assert "Usage:" in machine.fail("${machine}/bin/switch-to-configuration 2>&1")
687     with subtest("init interface version"):
688         # Do not try to switch to an invalid init interface version
689         assert "incompatible" in switch_to_specialisation("${machine}", "brokenInitInterface", fail=True)
691     with subtest("systemd restarts"):
692         # systemd is restarted when its system.conf changes
693         out = switch_to_specialisation("${machine}", "modifiedSystemConf")
694         assert_contains(out, "restarting systemd...")
696     with subtest("continuing from an aborted switch"):
697         # An aborted switch will write into a file what it tried to start
698         # and a second switch should continue from this
699         machine.succeed("echo ${dbusService} > /run/nixos/start-list")
700         out = switch_to_specialisation("${machine}", "modifiedSystemConf")
701         assert_contains(out, "starting the following units: ${dbusService}\n")
703     with subtest("fstab mounts"):
704         switch_to_specialisation("${machine}", "")
705         # add a mountpoint
706         out = switch_to_specialisation("${machine}", "addedMount")
707         assert_lacks(out, "stopping the following units:")
708         assert_lacks(out, "NOT restarting the following changed units:")
709         assert_lacks(out, "\nrestarting the following units:")
710         assert_lacks(out, "\nstarting the following units:")
711         assert_contains(out, "the following new units were started: test.mount\n")
712         # modify the mountpoint's options
713         out = switch_to_specialisation("${machine}", "addedMountOptsModified")
714         assert_lacks(out, "stopping the following units:")
715         assert_lacks(out, "NOT restarting the following changed units:")
716         assert_contains(out, "reloading the following units: test.mount\n")
717         assert_lacks(out, "\nrestarting the following units:")
718         assert_lacks(out, "\nstarting the following units:")
719         assert_lacks(out, "the following new units were started:")
720         # modify the device
721         out = switch_to_specialisation("${machine}", "addedMountDevModified")
722         assert_lacks(out, "stopping the following units:")
723         assert_lacks(out, "NOT restarting the following changed units:")
724         assert_lacks(out, "reloading the following units:")
725         assert_contains(out, "\nrestarting the following units: test.mount\n")
726         assert_lacks(out, "\nstarting the following units:")
727         assert_lacks(out, "the following new units were started:")
728         # modify both
729         out = switch_to_specialisation("${machine}", "addedMount")
730         assert_lacks(out, "stopping the following units:")
731         assert_lacks(out, "NOT restarting the following changed units:")
732         assert_lacks(out, "reloading the following units:")
733         assert_contains(out, "\nrestarting the following units: test.mount\n")
734         assert_lacks(out, "\nstarting the following units:")
735         assert_lacks(out, "the following new units were started:")
736         # remove the mount
737         out = switch_to_specialisation("${machine}", "")
738         assert_contains(out, "stopping the following units: test.mount\n")
739         assert_lacks(out, "NOT restarting the following changed units:")
740         assert_contains(out, "reloading the following units: ${dbusService}\n")
741         assert_lacks(out, "\nrestarting the following units:")
742         assert_lacks(out, "\nstarting the following units:")
743         assert_lacks(out, "the following new units were started:")
744         # change something about the / mount
745         out = switch_to_specialisation("${machine}", "storeMountModified")
746         assert_lacks(out, "stopping the following units:")
747         assert_contains(out, "NOT restarting the following changed units: -.mount")
748         assert_contains(out, "reloading the following units: ${dbusService}\n")
749         assert_lacks(out, "\nrestarting the following units:")
750         assert_lacks(out, "\nstarting the following units:")
751         assert_lacks(out, "the following new units were started:")
753     with subtest("swaps"):
754         switch_to_specialisation("${machine}", "")
755         # add a swap
756         out = switch_to_specialisation("${machine}", "swap")
757         assert_lacks(out, "stopping the following units:")
758         assert_lacks(out, "NOT restarting the following changed units:")
759         assert_contains(out, "reloading the following units: ${dbusService}\n")
760         assert_lacks(out, "\nrestarting the following units:")
761         assert_lacks(out, "\nstarting the following units:")
762         assert_contains(out, "the following new units were started: swapfile.swap")
763         # remove it
764         out = switch_to_specialisation("${machine}", "")
765         assert_contains(out, "stopping swap device: /swapfile")
766         assert_lacks(out, "stopping the following units:")
767         assert_lacks(out, "NOT restarting the following changed units:")
768         assert_contains(out, "reloading the following units: ${dbusService}\n")
769         assert_lacks(out, "\nrestarting the following units:")
770         assert_lacks(out, "\nstarting the following units:")
771         assert_lacks(out, "the following new units were started:")
773     with subtest("services"):
774         switch_to_specialisation("${machine}", "")
775         # Nothing happens when nothing is changed
776         out = switch_to_specialisation("${machine}", "")
777         assert_lacks(out, "stopping the following units:")
778         assert_lacks(out, "NOT restarting the following changed units:")
779         assert_lacks(out, "reloading the following units:")
780         assert_lacks(out, "\nrestarting the following units:")
781         assert_lacks(out, "\nstarting the following units:")
782         assert_lacks(out, "the following new units were started:")
784         # Start a simple service
785         out = switch_to_specialisation("${machine}", "simpleService")
786         assert_lacks(out, "installing dummy bootloader")  # test does not install a bootloader
787         assert_lacks(out, "stopping the following units:")
788         assert_lacks(out, "NOT restarting the following changed units:")
789         assert_contains(out, "reloading the following units: ${dbusService}\n")  # huh
790         assert_lacks(out, "\nrestarting the following units:")
791         assert_lacks(out, "\nstarting the following units:")
792         assert_contains(out, "the following new units were started: test.service\n")
794         # Not changing anything doesn't do anything
795         out = switch_to_specialisation("${machine}", "simpleService")
796         assert_lacks(out, "stopping the following units:")
797         assert_lacks(out, "NOT restarting the following changed units:")
798         assert_lacks(out, "reloading the following units:")
799         assert_lacks(out, "\nrestarting the following units:")
800         assert_lacks(out, "\nstarting the following units:")
801         assert_lacks(out, "the following new units were started:")
803         # Only changing the description does nothing
804         out = switch_to_specialisation("${machine}", "simpleServiceDifferentDescription")
805         assert_lacks(out, "stopping the following units:")
806         assert_lacks(out, "NOT restarting the following changed units:")
807         assert_lacks(out, "reloading the following units:")
808         assert_lacks(out, "\nrestarting the following units:")
809         assert_lacks(out, "\nstarting the following units:")
810         assert_lacks(out, "the following new units were started:")
812         # Restart the simple service
813         out = switch_to_specialisation("${machine}", "simpleServiceModified")
814         assert_contains(out, "stopping the following units: test.service\n")
815         assert_lacks(out, "NOT restarting the following changed units:")
816         assert_lacks(out, "reloading the following units:")
817         assert_lacks(out, "\nrestarting the following units:")
818         assert_contains(out, "\nstarting the following units: test.service\n")
819         assert_lacks(out, "the following new units were started:")
821         # Restart the service with stopIfChanged=false
822         out = switch_to_specialisation("${machine}", "simpleServiceNostop")
823         assert_lacks(out, "stopping the following units:")
824         assert_lacks(out, "NOT restarting the following changed units:")
825         assert_lacks(out, "reloading the following units:")
826         assert_contains(out, "\nrestarting the following units: test.service\n")
827         assert_lacks(out, "\nstarting the following units:")
828         assert_lacks(out, "the following new units were started:")
830         # Reload the service with reloadIfChanged=true
831         out = switch_to_specialisation("${machine}", "simpleServiceReload")
832         assert_lacks(out, "stopping the following units:")
833         assert_lacks(out, "NOT restarting the following changed units:")
834         assert_contains(out, "reloading the following units: test.service\n")
835         assert_lacks(out, "\nrestarting the following units:")
836         assert_lacks(out, "\nstarting the following units:")
837         assert_lacks(out, "the following new units were started:")
839         # Nothing happens when restartIfChanged=false
840         out = switch_to_specialisation("${machine}", "simpleServiceNorestart")
841         assert_lacks(out, "stopping the following units:")
842         assert_contains(out, "NOT restarting the following changed units: test.service\n")
843         assert_lacks(out, "reloading the following units:")
844         assert_lacks(out, "\nrestarting the following units:")
845         assert_lacks(out, "\nstarting the following units:")
846         assert_lacks(out, "the following new units were started:")
848         # Dry mode shows different messages
849         out = switch_to_specialisation("${machine}", "simpleService", action="dry-activate")
850         assert_lacks(out, "stopping the following units:")
851         assert_lacks(out, "NOT restarting the following changed units:")
852         assert_lacks(out, "reloading the following units:")
853         assert_lacks(out, "\nrestarting the following units:")
854         assert_lacks(out, "\nstarting the following units:")
855         assert_lacks(out, "the following new units were started:")
856         assert_contains(out, "would start the following units: test.service\n")
858         out = switch_to_specialisation("${machine}", "", action="test")
860         # Ensure the service can be started when the activation script isn't in toplevel
861         # This is a lot like "Start a simple service", except activation-only deps could be gc-ed
862         out = run_switch("${nodes.machine.specialisation.simpleServiceSeparateActivationScript.configuration.system.build.separateActivationScript}/bin/switch-to-configuration");
863         assert_lacks(out, "installing dummy bootloader")  # test does not install a bootloader
864         assert_lacks(out, "stopping the following units:")
865         assert_lacks(out, "NOT restarting the following changed units:")
866         assert_contains(out, "reloading the following units: ${dbusService}\n")  # huh
867         assert_lacks(out, "\nrestarting the following units:")
868         assert_lacks(out, "\nstarting the following units:")
869         assert_contains(out, "the following new units were started: test.service\n")
870         machine.succeed("! test -e /run/current-system/activate")
871         machine.succeed("! test -e /run/current-system/dry-activate")
872         machine.succeed("! test -e /run/current-system/bin/switch-to-configuration")
874         # Ensure \ works in unit names
875         out = switch_to_specialisation("${machine}", "unitWithBackslash")
876         assert_contains(out, "stopping the following units: test.service\n")
877         assert_lacks(out, "NOT restarting the following changed units:")
878         assert_lacks(out, "reloading the following units:")
879         assert_lacks(out, "\nrestarting the following units:")
880         assert_lacks(out, "\nstarting the following units:")
881         assert_contains(out, "the following new units were started: escaped\\x2ddash.service\n")
883         out = switch_to_specialisation("${machine}", "unitWithBackslashModified")
884         assert_contains(out, "stopping the following units: escaped\\x2ddash.service\n")
885         assert_lacks(out, "NOT restarting the following changed units:")
886         assert_lacks(out, "reloading the following units:")
887         assert_lacks(out, "\nrestarting the following units:")
888         assert_contains(out, "\nstarting the following units: escaped\\x2ddash.service\n")
889         assert_lacks(out, "the following new units were started:")
891         # Ensure units can start with a dash
892         out = switch_to_specialisation("${machine}", "unitStartingWithDash")
893         assert_contains(out, "stopping the following units: escaped\\x2ddash.service\n")
894         assert_lacks(out, "NOT restarting the following changed units:")
895         assert_lacks(out, "reloading the following units:")
896         assert_lacks(out, "\nrestarting the following units:")
897         assert_lacks(out, "\nstarting the following units:")
898         assert_contains(out, "the following new units were started: -.service\n")
900         # The regression only occurs when reloading units
901         out = switch_to_specialisation("${machine}", "unitStartingWithDashModified")
902         assert_lacks(out, "stopping the following units:")
903         assert_lacks(out, "NOT restarting the following changed units:")
904         assert_contains(out, "reloading the following units: -.service")
905         assert_lacks(out, "\nrestarting the following units:")
906         assert_lacks(out, "\nstarting the following units:")
907         assert_lacks(out, "the following new units were started:")
909         # Ensure units that require changed units are properly reloaded
910         out = switch_to_specialisation("${machine}", "unitWithRequirement")
911         assert_contains(out, "stopping the following units: -.service\n")
912         assert_lacks(out, "NOT restarting the following changed units:")
913         assert_lacks(out, "reloading the following units:")
914         assert_lacks(out, "\nrestarting the following units:")
915         assert_lacks(out, "\nstarting the following units:")
916         assert_contains(out, "the following new units were started: required-service.service, test-service.service\n")
918         out = switch_to_specialisation("${machine}", "unitWithRequirementModified")
919         assert_contains(out, "stopping the following units: required-service.service\n")
920         assert_lacks(out, "NOT restarting the following changed units:")
921         assert_lacks(out, "reloading the following units:")
922         assert_lacks(out, "\nrestarting the following units:")
923         assert_contains(out, "\nstarting the following units: required-service.service, test-service.service\n")
924         assert_lacks(out, "the following new units were started:")
926         # Unless the unit asks to be not restarted
927         out = switch_to_specialisation("${machine}", "unitWithRequirementModifiedNostart")
928         assert_contains(out, "stopping the following units: required-service.service\n")
929         assert_lacks(out, "NOT restarting the following changed units:")
930         assert_lacks(out, "reloading the following units:")
931         assert_lacks(out, "\nrestarting the following units:")
932         assert_contains(out, "\nstarting the following units: required-service.service\n")
933         assert_lacks(out, "the following new units were started:")
935         # Ensure templated units are restarted when the base unit changes
936         switch_to_specialisation("${machine}", "unitWithTemplate")
937         out = switch_to_specialisation("${machine}", "unitWithTemplateModified")
938         assert_contains(out, "stopping the following units: instantiated@one.service, instantiated@two.service\n")
939         assert_lacks(out, "NOT restarting the following changed units:")
940         assert_lacks(out, "reloading the following units:")
941         assert_lacks(out, "\nrestarting the following units:")
942         assert_contains(out, "\nstarting the following units: instantiated@one.service, instantiated@two.service\n")
943         assert_lacks(out, "the following new units were started:")
945     with subtest("failing units"):
946         # Let the simple service fail
947         switch_to_specialisation("${machine}", "simpleServiceModified")
948         out = switch_to_specialisation("${machine}", "simpleServiceFailing", fail=True)
949         assert_contains(out, "stopping the following units: test.service\n")
950         assert_lacks(out, "NOT restarting the following changed units:")
951         assert_lacks(out, "reloading the following units:")
952         assert_lacks(out, "\nrestarting the following units:")
953         assert_contains(out, "\nstarting the following units: test.service\n")
954         assert_lacks(out, "the following new units were started:")
955         assert_contains(out, "warning: the following units failed: test.service\n")
956         assert_contains(out, "Main PID:")  # output of systemctl
958         # A unit that gets into autorestart without failing is not treated as failed
959         out = switch_to_specialisation("${machine}", "autorestartService")
960         assert_lacks(out, "stopping the following units:")
961         assert_lacks(out, "NOT restarting the following changed units:")
962         assert_lacks(out, "reloading the following units:")
963         assert_lacks(out, "\nrestarting the following units:")
964         assert_lacks(out, "\nstarting the following units:")
965         assert_contains(out, "the following new units were started: autorestart.service\n")
966         machine.systemctl('stop autorestart.service')  # cancel the 20y timer
968         # Switching to the same system should do nothing (especially not treat the unit as failed)
969         out = switch_to_specialisation("${machine}", "autorestartService")
970         assert_lacks(out, "stopping the following units:")
971         assert_lacks(out, "NOT restarting the following changed units:")
972         assert_lacks(out, "reloading the following units:")
973         assert_lacks(out, "\nrestarting the following units:")
974         assert_lacks(out, "\nstarting the following units:")
975         assert_contains(out, "the following new units were started: autorestart.service\n")
976         machine.systemctl('stop autorestart.service')  # cancel the 20y timer
978         # If systemd thinks the unit has failed and is in autorestart, we should show it as failed
979         out = switch_to_specialisation("${machine}", "autorestartServiceFailing", fail=True)
980         assert_lacks(out, "stopping the following units:")
981         assert_lacks(out, "NOT restarting the following changed units:")
982         assert_lacks(out, "reloading the following units:")
983         assert_lacks(out, "\nrestarting the following units:")
984         assert_lacks(out, "\nstarting the following units:")
985         assert_lacks(out, "the following new units were started:")
986         assert_contains(out, "warning: the following units failed: autorestart.service\n")
987         assert_contains(out, "Main PID:")  # output of systemctl
989     with subtest("unit file parser"):
990         # Switch to a well-known state
991         switch_to_specialisation("${machine}", "simpleServiceNostop")
993         # Add a section
994         out = switch_to_specialisation("${machine}", "simpleServiceWithExtraSection")
995         assert_lacks(out, "stopping the following units:")
996         assert_lacks(out, "NOT restarting the following changed units:")
997         assert_lacks(out, "reloading the following units:")
998         assert_contains(out, "\nrestarting the following units: test.service\n")
999         assert_lacks(out, "\nstarting the following units:")
1000         assert_lacks(out, "the following new units were started:")
1002         # Rename it
1003         out = switch_to_specialisation("${machine}", "simpleServiceWithExtraSectionOtherName")
1004         assert_lacks(out, "stopping the following units:")
1005         assert_lacks(out, "NOT restarting the following changed units:")
1006         assert_lacks(out, "reloading the following units:")
1007         assert_contains(out, "\nrestarting the following units: test.service\n")
1008         assert_lacks(out, "\nstarting the following units:")
1009         assert_lacks(out, "the following new units were started:")
1011         # Remove it
1012         out = switch_to_specialisation("${machine}", "simpleServiceNostop")
1013         assert_lacks(out, "stopping the following units:")
1014         assert_lacks(out, "NOT restarting the following changed units:")
1015         assert_lacks(out, "reloading the following units:")
1016         assert_contains(out, "\nrestarting the following units: test.service\n")
1017         assert_lacks(out, "\nstarting the following units:")
1018         assert_lacks(out, "the following new units were started:")
1020         # [Install] section is ignored
1021         out = switch_to_specialisation("${machine}", "simpleServiceWithInstallSection")
1022         assert_lacks(out, "stopping the following units:")
1023         assert_lacks(out, "NOT restarting the following changed units:")
1024         assert_lacks(out, "reloading the following units:")
1025         assert_lacks(out, "\nrestarting the following units:")
1026         assert_lacks(out, "\nstarting the following units:")
1027         assert_lacks(out, "the following new units were started:")
1029         # Add a key
1030         out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKey")
1031         assert_lacks(out, "stopping the following units:")
1032         assert_lacks(out, "NOT restarting the following changed units:")
1033         assert_lacks(out, "reloading the following units:")
1034         assert_contains(out, "\nrestarting the following units: test.service\n")
1035         assert_lacks(out, "\nstarting the following units:")
1036         assert_lacks(out, "the following new units were started:")
1038         # Change its value
1039         out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKeyOtherValue")
1040         assert_lacks(out, "stopping the following units:")
1041         assert_lacks(out, "NOT restarting the following changed units:")
1042         assert_lacks(out, "reloading the following units:")
1043         assert_contains(out, "\nrestarting the following units: test.service\n")
1044         assert_lacks(out, "\nstarting the following units:")
1045         assert_lacks(out, "the following new units were started:")
1047         # Rename it
1048         out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKeyOtherName")
1049         assert_lacks(out, "stopping the following units:")
1050         assert_lacks(out, "NOT restarting the following changed units:")
1051         assert_lacks(out, "reloading the following units:")
1052         assert_contains(out, "\nrestarting the following units: test.service\n")
1053         assert_lacks(out, "\nstarting the following units:")
1054         assert_lacks(out, "the following new units were started:")
1056         # Remove it
1057         out = switch_to_specialisation("${machine}", "simpleServiceNostop")
1058         assert_lacks(out, "stopping the following units:")
1059         assert_lacks(out, "NOT restarting the following changed units:")
1060         assert_lacks(out, "reloading the following units:")
1061         assert_contains(out, "\nrestarting the following units: test.service\n")
1062         assert_lacks(out, "\nstarting the following units:")
1063         assert_lacks(out, "the following new units were started:")
1065         # Add a reload trigger
1066         out = switch_to_specialisation("${machine}", "simpleServiceReloadTrigger")
1067         assert_lacks(out, "stopping the following units:")
1068         assert_lacks(out, "NOT restarting the following changed units:")
1069         assert_contains(out, "reloading the following units: test.service\n")
1070         assert_lacks(out, "\nrestarting the following units:")
1071         assert_lacks(out, "\nstarting the following units:")
1072         assert_lacks(out, "the following new units were started:")
1074         # Modify the reload trigger
1075         out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModified")
1076         assert_lacks(out, "stopping the following units:")
1077         assert_lacks(out, "NOT restarting the following changed units:")
1078         assert_contains(out, "reloading the following units: test.service\n")
1079         assert_lacks(out, "\nrestarting the following units:")
1080         assert_lacks(out, "\nstarting the following units:")
1081         assert_lacks(out, "the following new units were started:")
1083         # Modify the reload trigger and something else
1084         out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModifiedAndSomethingElse")
1085         assert_lacks(out, "stopping the following units:")
1086         assert_lacks(out, "NOT restarting the following changed units:")
1087         assert_lacks(out, "reloading the following units:")
1088         assert_contains(out, "\nrestarting the following units: test.service\n")
1089         assert_lacks(out, "\nstarting the following units:")
1090         assert_lacks(out, "the following new units were started:")
1092         # Remove the reload trigger
1093         out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModifiedSomethingElse")
1094         assert_lacks(out, "stopping the following units:")
1095         assert_lacks(out, "NOT restarting the following changed units:")
1096         assert_lacks(out, "reloading the following units:")
1097         assert_lacks(out, "\nrestarting the following units:")
1098         assert_lacks(out, "\nstarting the following units:")
1099         assert_lacks(out, "the following new units were started:")
1101     with subtest("restart and reload by activation script"):
1102         switch_to_specialisation("${machine}", "simpleServiceNorestart")
1103         out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script")
1104         assert_contains(out, "stopping the following units: test.service\n")
1105         assert_lacks(out, "NOT restarting the following changed units:")
1106         assert_lacks(out, "reloading the following units:")
1107         assert_lacks(out, "restarting the following units:")
1108         assert_contains(out, "\nstarting the following units: ${sortedUnits [
1109           "no-restart-service.service"
1110           "reload-triggers-and-restart-by-as.service"
1111           "simple-reload-service.service"
1112           "simple-restart-service.service"
1113           "simple-service.service"
1114           "templated-no-restart-service@instance.service"
1115           "templated-reload-triggers-and-restart-by-as@instance.service"
1116           "templated-simple-reload-service@instance.service"
1117           "templated-simple-restart-service@instance.service"
1118           "templated-simple-service@instance.service"
1119         ]}\n")
1120         assert_contains(out, "the following new units were started: ${sortedUnits [
1121           "no-restart-service.service"
1122           "reload-triggers-and-restart-by-as.service"
1123           "reload-triggers-and-restart.service"
1124           "reload-triggers.service"
1125           "simple-reload-service.service"
1126           "simple-restart-service.service"
1127           "simple-service.service"
1128           "system-templated\\\\x2dno\\\\x2drestart\\\\x2dservice.slice"
1129           "system-templated\\\\x2dreload\\\\x2dtriggers.slice"
1130           "system-templated\\\\x2dreload\\\\x2dtriggers\\\\x2dand\\\\x2drestart.slice"
1131           "system-templated\\\\x2dreload\\\\x2dtriggers\\\\x2dand\\\\x2drestart\\\\x2dby\\\\x2das.slice"
1132           "system-templated\\\\x2dsimple\\\\x2dreload\\\\x2dservice.slice"
1133           "system-templated\\\\x2dsimple\\\\x2drestart\\\\x2dservice.slice"
1134           "system-templated\\\\x2dsimple\\\\x2dservice.slice"
1135           "templated-no-restart-service@instance.service"
1136           "templated-reload-triggers-and-restart-by-as@instance.service"
1137           "templated-reload-triggers-and-restart@instance.service"
1138           "templated-reload-triggers@instance.service"
1139           "templated-simple-reload-service@instance.service"
1140           "templated-simple-restart-service@instance.service"
1141           "templated-simple-service@instance.service"
1142         ]}\n")
1143         # Switch to the same system where the example services get restarted
1144         # and reloaded by the activation script
1145         out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script")
1146         assert_lacks(out, "stopping the following units:")
1147         assert_lacks(out, "NOT restarting the following changed units:")
1148         assert_contains(out, "reloading the following units: ${sortedUnits [
1149           "reload-triggers-and-restart.service"
1150           "reload-triggers.service"
1151           "simple-reload-service.service"
1152           "templated-reload-triggers-and-restart@instance.service"
1153           "templated-reload-triggers@instance.service"
1154           "templated-simple-reload-service@instance.service"
1155         ]}\n")
1156         assert_contains(out, "restarting the following units: ${sortedUnits [
1157           "reload-triggers-and-restart-by-as.service"
1158           "simple-restart-service.service"
1159           "simple-service.service"
1160           "templated-reload-triggers-and-restart-by-as@instance.service"
1161           "templated-simple-restart-service@instance.service"
1162           "templated-simple-service@instance.service"
1163         ]}\n")
1164         assert_lacks(out, "\nstarting the following units:")
1165         assert_lacks(out, "the following new units were started:")
1166         # Switch to the same system and see if the service gets restarted when it's modified
1167         # while the fact that it's supposed to be reloaded by the activation script is ignored.
1168         out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script-modified")
1169         assert_lacks(out, "stopping the following units:")
1170         assert_lacks(out, "NOT restarting the following changed units:")
1171         assert_contains(out, "reloading the following units: ${sortedUnits [
1172           "reload-triggers.service"
1173           "simple-reload-service.service"
1174           "templated-reload-triggers@instance.service"
1175           "templated-simple-reload-service@instance.service"
1176         ]}\n")
1177         assert_contains(out, "restarting the following units: ${sortedUnits [
1178           "reload-triggers-and-restart-by-as.service"
1179           "reload-triggers-and-restart.service"
1180           "simple-restart-service.service"
1181           "simple-service.service"
1182           "templated-reload-triggers-and-restart-by-as@instance.service"
1183           "templated-reload-triggers-and-restart@instance.service"
1184           "templated-simple-restart-service@instance.service"
1185           "templated-simple-service@instance.service"
1186         ]}\n")
1187         assert_lacks(out, "\nstarting the following units:")
1188         assert_lacks(out, "the following new units were started:")
1189         # The same, but in dry mode
1190         out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script", action="dry-activate")
1191         assert_lacks(out, "would stop the following units:")
1192         assert_lacks(out, "would NOT stop the following changed units:")
1193         assert_contains(out, "would reload the following units: ${sortedUnits [
1194           "reload-triggers.service"
1195           "simple-reload-service.service"
1196           "templated-reload-triggers@instance.service"
1197           "templated-simple-reload-service@instance.service"
1198         ]}\n")
1199         assert_contains(out, "would restart the following units: ${sortedUnits [
1200           "reload-triggers-and-restart-by-as.service"
1201           "reload-triggers-and-restart.service"
1202           "simple-restart-service.service"
1203           "simple-service.service"
1204           "templated-reload-triggers-and-restart-by-as@instance.service"
1205           "templated-reload-triggers-and-restart@instance.service"
1206           "templated-simple-restart-service@instance.service"
1207           "templated-simple-service@instance.service"
1208         ]}\n")
1209         assert_lacks(out, "\nwould start the following units:")
1211     with subtest("socket-activated services"):
1212         # Socket-activated services don't get started, just the socket
1213         machine.fail("[ -S /run/test.sock ]")
1214         out = switch_to_specialisation("${machine}", "simple-socket")
1215         # assert_lacks(out, "stopping the following units:") not relevant
1216         assert_lacks(out, "NOT restarting the following changed units:")
1217         assert_lacks(out, "reloading the following units:")
1218         assert_lacks(out, "\nrestarting the following units:")
1219         assert_lacks(out, "\nstarting the following units:")
1220         assert_contains(out, "the following new units were started: socket-activated.socket\n")
1221         machine.succeed("[ -S /run/test.sock ]")
1223         # Changing a non-activated service does nothing
1224         out = switch_to_specialisation("${machine}", "simple-socket-service-modified")
1225         assert_lacks(out, "stopping the following units:")
1226         assert_lacks(out, "NOT restarting the following changed units:")
1227         assert_lacks(out, "reloading the following units:")
1228         assert_lacks(out, "\nrestarting the following units:")
1229         assert_lacks(out, "\nstarting the following units:")
1230         assert_lacks(out, "the following new units were started:")
1231         machine.succeed("[ -S /run/test.sock ]")
1232         # The unit is properly activated when the socket is accessed
1233         if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
1234             raise Exception("Socket was not properly activated")  # idk how that would happen tbh
1236         # Changing an activated service with stopIfChanged=false restarts the service
1237         out = switch_to_specialisation("${machine}", "simple-socket")
1238         assert_lacks(out, "stopping the following units:")
1239         assert_lacks(out, "NOT restarting the following changed units:")
1240         assert_lacks(out, "reloading the following units:")
1241         assert_contains(out, "\nrestarting the following units: socket-activated.service\n")
1242         assert_lacks(out, "\nstarting the following units:")
1243         assert_lacks(out, "the following new units were started:")
1244         machine.succeed("[ -S /run/test.sock ]")
1245         # Socket-activation of the unit still works
1246         if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
1247             raise Exception("Socket was not properly activated after the service was restarted")
1249         # Changing an activated service with stopIfChanged=true stops the service and
1250         # socket and starts the socket
1251         out = switch_to_specialisation("${machine}", "simple-socket-stop-if-changed")
1252         assert_contains(out, "stopping the following units: socket-activated.service, socket-activated.socket\n")
1253         assert_lacks(out, "NOT restarting the following changed units:")
1254         assert_lacks(out, "reloading the following units:")
1255         assert_lacks(out, "\nrestarting the following units:")
1256         assert_contains(out, "\nstarting the following units: socket-activated.socket\n")
1257         assert_lacks(out, "the following new units were started:")
1258         machine.succeed("[ -S /run/test.sock ]")
1259         # Socket-activation of the unit still works
1260         if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
1261             raise Exception("Socket was not properly activated after the service was restarted")
1263         # Changing a reload trigger of a socket-activated unit only reloads it
1264         out = switch_to_specialisation("${machine}", "simple-socket-stop-if-changed-and-reloadtrigger")
1265         assert_lacks(out, "stopping the following units:")
1266         assert_lacks(out, "NOT restarting the following changed units:")
1267         assert_contains(out, "reloading the following units: socket-activated.service\n")
1268         assert_lacks(out, "\nrestarting the following units:")
1269         assert_lacks(out, "\nstarting the following units: socket-activated.socket")
1270         assert_lacks(out, "the following new units were started:")
1271         machine.succeed("[ -S /run/test.sock ]")
1272         # Socket-activation of the unit still works
1273         if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
1274             raise Exception("Socket was not properly activated after the service was restarted")
1276     with subtest("mounts"):
1277         switch_to_specialisation("${machine}", "mount")
1278         out = machine.succeed("mount | grep 'on /testmount'")
1279         assert_contains(out, "size=1024k")
1280         # Changing options reloads the unit
1281         out = switch_to_specialisation("${machine}", "mountOptionsModified")
1282         assert_lacks(out, "stopping the following units:")
1283         assert_lacks(out, "NOT restarting the following changed units:")
1284         assert_contains(out, "reloading the following units: testmount.mount\n")
1285         assert_lacks(out, "\nrestarting the following units:")
1286         assert_lacks(out, "\nstarting the following units:")
1287         assert_lacks(out, "the following new units were started:")
1288         # It changed
1289         out = machine.succeed("mount | grep 'on /testmount'")
1290         assert_contains(out, "size=10240k")
1291         # Changing anything but `Options=` restarts the unit
1292         out = switch_to_specialisation("${machine}", "mountModified")
1293         assert_lacks(out, "stopping the following units:")
1294         assert_lacks(out, "NOT restarting the following changed units:")
1295         assert_lacks(out, "reloading the following units:")
1296         assert_contains(out, "\nrestarting the following units: testmount.mount\n")
1297         assert_lacks(out, "\nstarting the following units:")
1298         assert_lacks(out, "the following new units were started:")
1299         # It changed
1300         out = machine.succeed("mount | grep 'on /testmount'")
1301         assert_contains(out, "ramfs")
1303     with subtest("timers"):
1304         switch_to_specialisation("${machine}", "timer")
1305         out = machine.succeed("systemctl show test-timer.timer")
1306         assert_contains(out, "OnCalendar=2014-03-25 02:59:56 UTC")
1307         out = switch_to_specialisation("${machine}", "timerModified")
1308         assert_lacks(out, "stopping the following units:")
1309         assert_lacks(out, "NOT restarting the following units:")
1310         assert_lacks(out, "reloading the following units:")
1311         assert_contains(out, "\nrestarting the following units: test-timer.timer\n")
1312         assert_lacks(out, "\nstarting the following units:")
1313         assert_lacks(out, "the following new units were started:")
1314         # It changed
1315         out = machine.succeed("systemctl show test-timer.timer")
1316         assert_contains(out, "OnCalendar=Fri 2012-11-23 16:00:00")
1318     with subtest("targets"):
1319         # Modifying some special targets like hybrid-sleep.target does nothing
1320         out = switch_to_specialisation("${machine}", "hybridSleepModified")
1321         assert_contains(out, "stopping the following units: test-timer.timer\n")
1322         assert_lacks(out, "NOT restarting the following changed units:")
1323         assert_lacks(out, "reloading the following units:")
1324         assert_lacks(out, "\nrestarting the following units:")
1325         assert_lacks(out, "\nstarting the following units:")
1326         assert_lacks(out, "the following new units were started:")
1328         # Adding a new target starts it
1329         out = switch_to_specialisation("${machine}", "target")
1330         assert_lacks(out, "stopping the following units:")
1331         assert_lacks(out, "NOT restarting the following changed units:")
1332         assert_lacks(out, "reloading the following units:")
1333         assert_lacks(out, "\nrestarting the following units:")
1334         assert_lacks(out, "\nstarting the following units:")
1335         assert_contains(out, "the following new units were started: test-target.target\n")
1337         # Changing a target doesn't print anything because the unit is filtered
1338         machine.systemctl("start test-service.service")
1339         out = switch_to_specialisation("${machine}", "targetModified")
1340         assert_lacks(out, "stopping the following units:")
1341         assert_lacks(out, "NOT restarting the following changed units:")
1342         assert_lacks(out, "reloading the following units:")
1343         assert_lacks(out, "\nrestarting the following units:")
1344         assert_lacks(out, "\nstarting the following units:")
1345         assert_lacks(out, "the following new units were started:")
1346         machine.succeed("systemctl is-active test-service.service")  # target was not restarted
1348         # With X-StopOnReconfiguration, the target gets stopped and started
1349         out = switch_to_specialisation("${machine}", "targetModifiedStopOnReconfig")
1350         assert_lacks(out, "stopping the following units:")
1351         assert_lacks(out, "NOT restarting the following changed units:")
1352         assert_lacks(out, "reloading the following units:")
1353         assert_lacks(out, "\nrestarting the following units:")
1354         assert_lacks(out, "\nstarting the following units:")
1355         assert_lacks(out, "the following new units were started:")
1356         machine.fail("systemctl is-active test-service.servce")  # target was restarted
1358         # Remove the target by switching to the old specialisation
1359         out = switch_to_specialisation("${machine}", "timerModified")
1360         assert_contains(out, "stopping the following units: test-target.target\n")
1361         assert_lacks(out, "NOT restarting the following changed units:")
1362         assert_lacks(out, "reloading the following units:")
1363         assert_lacks(out, "\nrestarting the following units:")
1364         assert_lacks(out, "\nstarting the following units:")
1365         assert_contains(out, "the following new units were started: test-timer.timer\n")
1367     with subtest("paths"):
1368         out = switch_to_specialisation("${machine}", "path")
1369         assert_contains(out, "stopping the following units: test-timer.timer\n")
1370         assert_lacks(out, "NOT restarting the following changed units:")
1371         assert_lacks(out, "reloading the following units:")
1372         assert_lacks(out, "\nrestarting the following units:")
1373         assert_lacks(out, "\nstarting the following units:")
1374         assert_contains(out, "the following new units were started: test-watch.path\n")
1375         machine.fail("test -f /testpath-modified")
1377         # touch the file, unit should be triggered
1378         machine.succeed("touch /testpath")
1379         machine.wait_until_succeeds("test -f /testpath-modified")
1380         machine.succeed("rm /testpath /testpath-modified")
1381         machine.systemctl("stop test-watch.service")
1382         switch_to_specialisation("${machine}", "pathModified")
1383         machine.succeed("touch /testpath")
1384         machine.fail("test -f /testpath-modified")
1385         machine.succeed("touch /testpath2")
1386         machine.wait_until_succeeds("test -f /testpath-modified")
1388     # This test ensures that changes to slice configuration get applied.
1389     # We test this by having a slice that allows no memory allocation at
1390     # all and starting a service within it. If the service crashes, the slice
1391     # is applied and if we modify the slice to allow memory allocation, the
1392     # service should successfully start.
1393     with subtest("slices"):
1394         machine.succeed("echo 0 > /proc/sys/vm/panic_on_oom")  # allow OOMing
1395         out = switch_to_specialisation("${machine}", "slice")
1396         # assert_lacks(out, "stopping the following units:") not relevant
1397         assert_lacks(out, "NOT restarting the following changed units:")
1398         assert_lacks(out, "reloading the following units:")
1399         assert_lacks(out, "\nrestarting the following units:")
1400         assert_lacks(out, "\nstarting the following units:")
1401         assert_lacks(out, "the following new units were started:")
1402         machine.fail("systemctl start testservice.service")
1404         out = switch_to_specialisation("${machine}", "sliceModified")
1405         assert_lacks(out, "stopping the following units:")
1406         assert_lacks(out, "NOT restarting the following changed units:")
1407         assert_lacks(out, "reloading the following units:")
1408         assert_lacks(out, "\nrestarting the following units:")
1409         assert_lacks(out, "\nstarting the following units:")
1410         assert_lacks(out, "the following new units were started:")
1411         machine.succeed("systemctl start testservice.service")
1412         machine.succeed("echo 1 > /proc/sys/vm/panic_on_oom")  # disallow OOMing
1413   '';