diff options
Diffstat (limited to 'nixos/tests/switch-test.nix')
-rw-r--r-- | nixos/tests/switch-test.nix | 420 |
1 files changed, 418 insertions, 2 deletions
diff --git a/nixos/tests/switch-test.nix b/nixos/tests/switch-test.nix index daad9134885f7..4f297b6521d17 100644 --- a/nixos/tests/switch-test.nix +++ b/nixos/tests/switch-test.nix @@ -18,6 +18,7 @@ import ./make-test-python.nix ({ pkgs, ...} : { Type = "oneshot"; RemainAfterExit = true; ExecStart = "${pkgs.coreutils}/bin/true"; + ExecReload = "${pkgs.coreutils}/bin/true"; }; }; }; @@ -45,6 +46,191 @@ import ./make-test-python.nix ({ pkgs, ...} : { systemd.services.test.restartIfChanged = false; }; + simpleServiceFailing.configuration = { + imports = [ simpleServiceModified.configuration ]; + systemd.services.test.serviceConfig.ExecStart = lib.mkForce "${pkgs.coreutils}/bin/false"; + }; + + autorestartService.configuration = { + # A service that immediately goes into restarting (but without failing) + systemd.services.autorestart = { + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + Restart = "always"; + RestartSec = "20y"; # Should be long enough + ExecStart = "${pkgs.coreutils}/bin/true"; + }; + }; + }; + + autorestartServiceFailing.configuration = { + imports = [ autorestartService.configuration ]; + systemd.services.autorestart.serviceConfig = { + ExecStart = lib.mkForce "${pkgs.coreutils}/bin/false"; + }; + }; + + simpleServiceWithExtraSection.configuration = { + imports = [ simpleServiceNostop.configuration ]; + systemd.packages = [ (pkgs.writeTextFile { + name = "systemd-extra-section"; + destination = "/etc/systemd/system/test.service"; + text = '' + [X-Test] + X-Test-Value=a + ''; + }) ]; + }; + + simpleServiceWithExtraSectionOtherName.configuration = { + imports = [ simpleServiceNostop.configuration ]; + systemd.packages = [ (pkgs.writeTextFile { + name = "systemd-extra-section"; + destination = "/etc/systemd/system/test.service"; + text = '' + [X-Test2] + X-Test-Value=a + ''; + }) ]; + }; + + simpleServiceWithInstallSection.configuration = { + imports = [ simpleServiceNostop.configuration ]; + systemd.packages = [ (pkgs.writeTextFile { + name = "systemd-extra-section"; + destination = "/etc/systemd/system/test.service"; + text = '' + [Install] + WantedBy=multi-user.target + ''; + }) ]; + }; + + simpleServiceWithExtraKey.configuration = { + imports = [ simpleServiceNostop.configuration ]; + systemd.services.test.serviceConfig."X-Test" = "test"; + }; + + simpleServiceWithExtraKeyOtherValue.configuration = { + imports = [ simpleServiceNostop.configuration ]; + systemd.services.test.serviceConfig."X-Test" = "test2"; + }; + + simpleServiceWithExtraKeyOtherName.configuration = { + imports = [ simpleServiceNostop.configuration ]; + systemd.services.test.serviceConfig."X-Test2" = "test"; + }; + + simpleServiceReloadTrigger.configuration = { + imports = [ simpleServiceNostop.configuration ]; + systemd.services.test.reloadTriggers = [ "/dev/null" ]; + }; + + simpleServiceReloadTriggerModified.configuration = { + imports = [ simpleServiceNostop.configuration ]; + systemd.services.test.reloadTriggers = [ "/dev/zero" ]; + }; + + simpleServiceReloadTriggerModifiedAndSomethingElse.configuration = { + imports = [ simpleServiceNostop.configuration ]; + systemd.services.test = { + reloadTriggers = [ "/dev/zero" ]; + serviceConfig."X-Test" = "test"; + }; + }; + + simpleServiceReloadTriggerModifiedSomethingElse.configuration = { + imports = [ simpleServiceNostop.configuration ]; + systemd.services.test.serviceConfig."X-Test" = "test"; + }; + + unitWithBackslash.configuration = { + systemd.services."escaped\\x2ddash" = { + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${pkgs.coreutils}/bin/true"; + ExecReload = "${pkgs.coreutils}/bin/true"; + }; + }; + }; + + unitWithBackslashModified.configuration = { + imports = [ unitWithBackslash.configuration ]; + systemd.services."escaped\\x2ddash".serviceConfig.X-Test = "test"; + }; + + restart-and-reload-by-activation-script.configuration = { + systemd.services = rec { + simple-service = { + # No wantedBy so we can check if the activation script restart triggers them + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${pkgs.coreutils}/bin/true"; + ExecReload = "${pkgs.coreutils}/bin/true"; + }; + }; + + simple-restart-service = simple-service // { + stopIfChanged = false; + }; + + simple-reload-service = simple-service // { + reloadIfChanged = true; + }; + + no-restart-service = simple-service // { + restartIfChanged = false; + }; + + reload-triggers = simple-service // { + wantedBy = [ "multi-user.target" ]; + }; + + reload-triggers-and-restart-by-as = simple-service; + + reload-triggers-and-restart = simple-service // { + stopIfChanged = false; # easier to check for this + wantedBy = [ "multi-user.target" ]; + }; + }; + + system.activationScripts.restart-and-reload-test = { + supportsDryActivation = true; + deps = []; + text = '' + if [ "$NIXOS_ACTION" = dry-activate ]; then + f=/run/nixos/dry-activation-restart-list + g=/run/nixos/dry-activation-reload-list + else + f=/run/nixos/activation-restart-list + g=/run/nixos/activation-reload-list + fi + cat <<EOF >> "$f" + simple-service.service + simple-restart-service.service + simple-reload-service.service + no-restart-service.service + reload-triggers-and-restart-by-as.service + EOF + + cat <<EOF >> "$g" + reload-triggers.service + reload-triggers-and-restart-by-as.service + reload-triggers-and-restart.service + EOF + ''; + }; + }; + + restart-and-reload-by-activation-script-modified.configuration = { + imports = [ restart-and-reload-by-activation-script.configuration ]; + systemd.services.reload-triggers-and-restart.serviceConfig.X-Modified = "test"; + }; + mount.configuration = { systemd.mounts = [ { @@ -145,12 +331,13 @@ import ./make-test-python.nix ({ pkgs, ...} : { exec env -i "$@" | tee /dev/stderr ''; in /* python */ '' - def switch_to_specialisation(system, name, action="test"): + def switch_to_specialisation(system, name, action="test", fail=False): if name == "": stc = f"{system}/bin/switch-to-configuration" else: stc = f"{system}/specialisation/{name}/bin/switch-to-configuration" - out = machine.succeed(f"{stc} {action} 2>&1") + out = machine.fail(f"{stc} {action} 2>&1") if fail \ + else machine.succeed(f"{stc} {action} 2>&1") assert_lacks(out, "switch-to-configuration line") # Perl warnings return out @@ -171,6 +358,8 @@ import ./make-test-python.nix ({ pkgs, ...} : { raise Exception(f"Unexpected string '{needle}' was found") + machine.wait_for_unit("multi-user.target") + machine.succeed( "${stderrRunner} ${originalSystem}/bin/switch-to-configuration test" ) @@ -261,6 +450,233 @@ import ./make-test-python.nix ({ pkgs, ...} : { assert_lacks(out, "as well:") assert_contains(out, "would start the following units: test.service\n") + # Ensure \ works in unit names + out = switch_to_specialisation("${machine}", "unitWithBackslash") + assert_contains(out, "stopping the following units: test.service\n") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_lacks(out, "\nrestarting the following units:") + assert_lacks(out, "\nstarting the following units:") + assert_contains(out, "the following new units were started: escaped\\x2ddash.service\n") + assert_lacks(out, "as well:") + + out = switch_to_specialisation("${machine}", "unitWithBackslashModified") + assert_contains(out, "stopping the following units: escaped\\x2ddash.service\n") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_lacks(out, "\nrestarting the following units:") + assert_contains(out, "\nstarting the following units: escaped\\x2ddash.service\n") + assert_lacks(out, "the following new units were started:") + assert_lacks(out, "as well:") + + with subtest("failing units"): + # Let the simple service fail + switch_to_specialisation("${machine}", "simpleServiceModified") + out = switch_to_specialisation("${machine}", "simpleServiceFailing", fail=True) + assert_contains(out, "stopping the following units: test.service\n") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_lacks(out, "\nrestarting the following units:") + assert_contains(out, "\nstarting the following units: test.service\n") + assert_lacks(out, "the following new units were started:") + assert_contains(out, "warning: the following units failed: test.service\n") + assert_contains(out, "Main PID:") # output of systemctl + assert_lacks(out, "as well:") + + # A unit that gets into autorestart without failing is not treated as failed + out = switch_to_specialisation("${machine}", "autorestartService") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_lacks(out, "\nrestarting the following units:") + assert_lacks(out, "\nstarting the following units:") + assert_contains(out, "the following new units were started: autorestart.service\n") + assert_lacks(out, "as well:") + machine.systemctl('stop autorestart.service') # cancel the 20y timer + + # Switching to the same system should do nothing (especially not treat the unit as failed) + out = switch_to_specialisation("${machine}", "autorestartService") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_lacks(out, "\nrestarting the following units:") + assert_lacks(out, "\nstarting the following units:") + assert_contains(out, "the following new units were started: autorestart.service\n") + assert_lacks(out, "as well:") + machine.systemctl('stop autorestart.service') # cancel the 20y timer + + # If systemd thinks the unit has failed and is in autorestart, we should show it as failed + out = switch_to_specialisation("${machine}", "autorestartServiceFailing", fail=True) + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_lacks(out, "\nrestarting the following units:") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "the following new units were started:") + assert_contains(out, "warning: the following units failed: autorestart.service\n") + assert_contains(out, "Main PID:") # output of systemctl + assert_lacks(out, "as well:") + + with subtest("unit file parser"): + # Switch to a well-known state + switch_to_specialisation("${machine}", "simpleServiceNostop") + + # Add a section + out = switch_to_specialisation("${machine}", "simpleServiceWithExtraSection") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_contains(out, "\nrestarting the following units: test.service\n") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "the following new units were started:") + assert_lacks(out, "as well:") + + # Rename it + out = switch_to_specialisation("${machine}", "simpleServiceWithExtraSectionOtherName") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_contains(out, "\nrestarting the following units: test.service\n") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "the following new units were started:") + assert_lacks(out, "as well:") + + # Remove it + out = switch_to_specialisation("${machine}", "simpleServiceNostop") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_contains(out, "\nrestarting the following units: test.service\n") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "the following new units were started:") + assert_lacks(out, "as well:") + + # [Install] section is ignored + out = switch_to_specialisation("${machine}", "simpleServiceWithInstallSection") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_lacks(out, "\nrestarting the following units:") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "the following new units were started:") + assert_lacks(out, "as well:") + + # Add a key + out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKey") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_contains(out, "\nrestarting the following units: test.service\n") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "the following new units were started:") + assert_lacks(out, "as well:") + + # Change its value + out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKeyOtherValue") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_contains(out, "\nrestarting the following units: test.service\n") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "the following new units were started:") + assert_lacks(out, "as well:") + + # Rename it + out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKeyOtherName") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_contains(out, "\nrestarting the following units: test.service\n") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "the following new units were started:") + assert_lacks(out, "as well:") + + # Remove it + out = switch_to_specialisation("${machine}", "simpleServiceNostop") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_contains(out, "\nrestarting the following units: test.service\n") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "the following new units were started:") + assert_lacks(out, "as well:") + + # Add a reload trigger + out = switch_to_specialisation("${machine}", "simpleServiceReloadTrigger") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_contains(out, "reloading the following units: test.service\n") + assert_lacks(out, "\nrestarting the following units:") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "the following new units were started:") + assert_lacks(out, "as well:") + + # Modify the reload trigger + out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModified") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_contains(out, "reloading the following units: test.service\n") + assert_lacks(out, "\nrestarting the following units:") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "the following new units were started:") + assert_lacks(out, "as well:") + + # Modify the reload trigger and something else + out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModifiedAndSomethingElse") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_contains(out, "\nrestarting the following units: test.service\n") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "the following new units were started:") + assert_lacks(out, "as well:") + + # Remove the reload trigger + out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModifiedSomethingElse") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_lacks(out, "\nrestarting the following units:") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "the following new units were started:") + assert_lacks(out, "as well:") + + with subtest("restart and reload by activation script"): + switch_to_specialisation("${machine}", "simpleServiceNorestart") + out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script") + assert_contains(out, "stopping the following units: test.service\n") + assert_lacks(out, "NOT restarting the following changed units:") + assert_lacks(out, "reloading the following units:") + assert_lacks(out, "restarting the following units:") + assert_contains(out, "\nstarting the following units: no-restart-service.service, reload-triggers-and-restart-by-as.service, simple-reload-service.service, simple-restart-service.service, simple-service.service\n") + assert_lacks(out, "as well:") + # Switch to the same system where the example services get restarted + # and reloaded by the activation script + out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_contains(out, "reloading the following units: reload-triggers-and-restart.service, reload-triggers.service, simple-reload-service.service\n") + assert_contains(out, "restarting the following units: reload-triggers-and-restart-by-as.service, simple-restart-service.service, simple-service.service\n") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "as well:") + # Switch to the same system and see if the service gets restarted when it's modified + # while the fact that it's supposed to be reloaded by the activation script is ignored. + out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script-modified") + assert_lacks(out, "stopping the following units:") + assert_lacks(out, "NOT restarting the following changed units:") + assert_contains(out, "reloading the following units: reload-triggers.service, simple-reload-service.service\n") + assert_contains(out, "restarting the following units: reload-triggers-and-restart-by-as.service, reload-triggers-and-restart.service, simple-restart-service.service, simple-service.service\n") + assert_lacks(out, "\nstarting the following units:") + assert_lacks(out, "as well:") + # The same, but in dry mode + out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script", action="dry-activate") + assert_lacks(out, "would stop the following units:") + assert_lacks(out, "would NOT stop the following changed units:") + assert_contains(out, "would reload the following units: reload-triggers.service, simple-reload-service.service\n") + assert_contains(out, "would restart the following units: reload-triggers-and-restart-by-as.service, reload-triggers-and-restart.service, simple-restart-service.service, simple-service.service\n") + assert_lacks(out, "\nwould start the following units:") + assert_lacks(out, "as well:") + with subtest("mounts"): switch_to_specialisation("${machine}", "mount") out = machine.succeed("mount | grep 'on /testmount'") |