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