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