nixos/tests/hibernate: install a system instead
Rather than relying on carefully avoiding touching the 9P-mounted /nix/store, we instead install a small NixOS system, similar to the installer tests, and boot from that. This avoids the various pitfalls associated with trying to unsuspend properly and trades off a bunch of boilerplate for what will hopefully be a more reliable test. Additionally, this test now actually tests booting the system using a bootloader, rather than the previous method of just booting the kernel directly.
This commit is contained in:
parent
bdf8e0fc31
commit
32d80aaaa5
@ -1,44 +1,120 @@
|
||||
# Test whether hibernation from partition works.
|
||||
|
||||
import ./make-test-python.nix (pkgs: {
|
||||
{ system ? builtins.currentSystem
|
||||
, config ? {}
|
||||
, pkgs ? import ../.. { inherit system config; }
|
||||
}:
|
||||
|
||||
with import ../lib/testing-python.nix { inherit system pkgs; };
|
||||
|
||||
let
|
||||
# System configuration of the installed system, which is used for the actual
|
||||
# hibernate testing.
|
||||
installedConfig = with pkgs.lib; {
|
||||
imports = [
|
||||
../modules/testing/test-instrumentation.nix
|
||||
../modules/profiles/qemu-guest.nix
|
||||
../modules/profiles/minimal.nix
|
||||
];
|
||||
|
||||
hardware.enableAllFirmware = mkForce false;
|
||||
documentation.nixos.enable = false;
|
||||
boot.loader.grub.device = "/dev/vda";
|
||||
|
||||
systemd.services.backdoor.conflicts = [ "sleep.target" ];
|
||||
|
||||
powerManagement.resumeCommands = "systemctl --no-block restart backdoor.service";
|
||||
|
||||
fileSystems = {
|
||||
"/".device = "/dev/vda2";
|
||||
};
|
||||
swapDevices = mkOverride 0 [ { device = "/dev/vda1"; } ];
|
||||
};
|
||||
installedSystem = (import ../lib/eval-config.nix {
|
||||
inherit system;
|
||||
modules = [ installedConfig ];
|
||||
}).config.system.build.toplevel;
|
||||
in makeTest {
|
||||
name = "hibernate";
|
||||
|
||||
nodes = {
|
||||
# System configuration used for installing the installedConfig from above.
|
||||
machine = { config, lib, pkgs, ... }: with lib; {
|
||||
virtualisation.emptyDiskImages = [ config.virtualisation.memorySize ];
|
||||
imports = [
|
||||
../modules/profiles/installation-device.nix
|
||||
../modules/profiles/base.nix
|
||||
];
|
||||
|
||||
systemd.services.backdoor.conflicts = [ "sleep.target" ];
|
||||
nix.binaryCaches = mkForce [ ];
|
||||
nix.extraOptions = ''
|
||||
hashed-mirrors =
|
||||
connect-timeout = 1
|
||||
'';
|
||||
|
||||
swapDevices = mkOverride 0 [ { device = "/dev/vdb"; } ];
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 4444 ];
|
||||
|
||||
systemd.services.listener.serviceConfig.ExecStart = "${pkgs.netcat}/bin/nc -l 4444 -k";
|
||||
};
|
||||
|
||||
probe = { pkgs, ...}: {
|
||||
environment.systemPackages = [ pkgs.netcat ];
|
||||
virtualisation.diskSize = 8 * 1024;
|
||||
virtualisation.emptyDiskImages = [
|
||||
# Small root disk for installer
|
||||
512
|
||||
];
|
||||
virtualisation.bootDevice = "/dev/vdb";
|
||||
};
|
||||
};
|
||||
|
||||
# 9P doesn't support reconnection to virtio transport after a hibernation.
|
||||
# Therefore, machine just hangs on any Nix store access.
|
||||
# To work around it we run a daemon which listens to a TCP connection and
|
||||
# try to connect to it as a test.
|
||||
# To avoid this, we install NixOS onto a temporary disk with everything we need
|
||||
# included into the store.
|
||||
|
||||
testScript =
|
||||
''
|
||||
def create_named_machine(name):
|
||||
return create_machine(
|
||||
{
|
||||
"qemuFlags": "-cpu max ${
|
||||
if system == "x86_64-linux" then "-m 1024"
|
||||
else "-m 768 -enable-kvm -machine virt,gic-version=host"}",
|
||||
"hdaInterface": "virtio",
|
||||
"hda": "vm-state-machine/machine.qcow2",
|
||||
"name": name,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
# Install NixOS
|
||||
machine.start()
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
machine.succeed("mkswap /dev/vdb")
|
||||
machine.succeed("swapon -a")
|
||||
machine.start_job("listener")
|
||||
machine.wait_for_open_port(4444)
|
||||
machine.succeed("systemctl hibernate &")
|
||||
machine.wait_for_shutdown()
|
||||
probe.wait_for_unit("multi-user.target")
|
||||
machine.start()
|
||||
probe.wait_until_succeeds("echo test | nc machine 4444 -N")
|
||||
machine.succeed(
|
||||
# Partition /dev/vda
|
||||
"flock /dev/vda parted --script /dev/vda -- mklabel msdos"
|
||||
+ " mkpart primary linux-swap 1M 1024M"
|
||||
+ " mkpart primary ext2 1024M -1s",
|
||||
"udevadm settle",
|
||||
"mkfs.ext3 -L nixos /dev/vda2",
|
||||
"mount LABEL=nixos /mnt",
|
||||
"mkswap /dev/vda1 -L swap",
|
||||
# Install onto /mnt
|
||||
"nix-store --load-db < ${pkgs.closureInfo {rootPaths = [installedSystem];}}/registration",
|
||||
"nixos-install --root /mnt --system ${installedSystem} --no-root-passwd",
|
||||
)
|
||||
machine.shutdown()
|
||||
|
||||
# Start up
|
||||
hibernate = create_named_machine("hibernate")
|
||||
|
||||
# Drop in file that checks if we un-hibernated properly (and not booted fresh)
|
||||
hibernate.succeed(
|
||||
"mkdir /run/test",
|
||||
"mount -t ramfs -o size=1m ramfs /run/test",
|
||||
"echo not persisted to disk > /run/test/suspended",
|
||||
)
|
||||
|
||||
# Hibernate machine
|
||||
hibernate.succeed("systemctl hibernate &")
|
||||
hibernate.wait_for_shutdown()
|
||||
|
||||
# Restore machine from hibernation, validate our ramfs file is there.
|
||||
resume = create_named_machine("resume")
|
||||
resume.start()
|
||||
resume.succeed("grep 'not persisted to disk' /run/test/suspended")
|
||||
'';
|
||||
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user