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