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.
		
			
				
	
	
		
			121 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
# Test whether hibernation from partition works.
 | 
						|
 | 
						|
{ 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; {
 | 
						|
      imports = [
 | 
						|
        ../modules/profiles/installation-device.nix
 | 
						|
        ../modules/profiles/base.nix
 | 
						|
      ];
 | 
						|
 | 
						|
      nix.binaryCaches = mkForce [ ];
 | 
						|
      nix.extraOptions = ''
 | 
						|
        hashed-mirrors =
 | 
						|
        connect-timeout = 1
 | 
						|
      '';
 | 
						|
 | 
						|
      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 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.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")
 | 
						|
    '';
 | 
						|
 | 
						|
}
 |