1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
3 ;;; Copyright © 2017, 2019 Tobias Geerinckx-Rice <me@tobias.gr>
4 ;;; Copyright © 2020 Mathieu Othacehe <m.othacehe@gmail.com>
5 ;;; Copyright © 2020 Danny Milosavljevic <dannym@scratchpost.org>
6 ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
8 ;;; This file is part of GNU Guix.
10 ;;; GNU Guix is free software; you can redistribute it and/or modify it
11 ;;; under the terms of the GNU General Public License as published by
12 ;;; the Free Software Foundation; either version 3 of the License, or (at
13 ;;; your option) any later version.
15 ;;; GNU Guix is distributed in the hope that it will be useful, but
16 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;;; GNU General Public License for more details.
20 ;;; You should have received a copy of the GNU General Public License
21 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
23 (define-module (gnu tests install)
25 #:use-module (gnu bootloader extlinux)
26 #:use-module (gnu image)
27 #:use-module (gnu tests)
28 #:use-module (gnu tests base)
29 #:use-module (gnu system)
30 #:use-module (gnu system image)
31 #:use-module (gnu system install)
32 #:use-module (gnu system vm)
33 #:use-module ((gnu build vm) #:select (qemu-command))
34 #:use-module (gnu packages admin)
35 #:use-module (gnu packages bootloaders)
36 #:use-module (gnu packages commencement) ;for 'guile-final'
37 #:use-module (gnu packages cryptsetup)
38 #:use-module (gnu packages linux)
39 #:use-module (gnu packages ocr)
40 #:use-module (gnu packages openbox)
41 #:use-module (gnu packages package-management)
42 #:use-module (gnu packages ratpoison)
43 #:use-module (gnu packages suckless)
44 #:use-module (gnu packages virtualization)
45 #:use-module (gnu packages wm)
46 #:use-module (gnu packages xorg)
47 #:use-module (gnu services desktop)
48 #:use-module (gnu services networking)
49 #:use-module (gnu services xorg)
50 #:use-module (guix store)
51 #:use-module (guix monads)
52 #:use-module (guix packages)
53 #:use-module (guix grafts)
54 #:use-module (guix gexp)
55 #:use-module (guix utils)
56 #:use-module (srfi srfi-1)
57 #:export (%test-installed-os
58 %test-installed-extlinux-os
59 %test-iso-image-installer
60 %test-separate-store-os
61 %test-separate-home-os
63 %test-encrypted-root-os
65 %test-btrfs-root-on-subvolume-os
69 %test-gui-installed-os
70 %test-gui-installed-os-encrypted
71 %test-gui-installed-desktop-os-encrypted))
75 ;;; Test the installation of Guix using the documented approach at the
80 (define-os-with-source (%minimal-os %minimal-os-source)
81 ;; The OS we want to install.
82 (use-modules (gnu) (gnu tests) (srfi srfi-1))
85 (host-name "liberigilo")
86 (timezone "Europe/Paris")
87 (locale "en_US.UTF-8")
89 (bootloader (bootloader-configuration
90 (bootloader grub-bootloader)
92 (kernel-arguments '("console=ttyS0"))
93 (file-systems (cons (file-system
94 (device (file-system-label "my-root"))
98 (users (cons (user-account
100 (comment "Bob's sister")
102 (supplementary-groups '("wheel" "audio" "video")))
103 %base-user-accounts))
104 (services (cons (service marionette-service-type
105 (marionette-configuration
106 (imported-modules '((gnu services herd)
108 (guix combinators)))))
111 (define (operating-system-add-packages os packages)
112 "Append PACKAGES to OS packages list."
115 (packages (append packages (operating-system-packages os)))))
117 (define-os-with-source (%minimal-extlinux-os
118 %minimal-extlinux-os-source)
119 (use-modules (gnu) (gnu tests) (gnu bootloader extlinux)
123 (host-name "liberigilo")
124 (timezone "Europe/Paris")
125 (locale "en_US.UTF-8")
127 (bootloader (bootloader-configuration
128 (bootloader extlinux-bootloader-gpt)
129 (target "/dev/vdb")))
130 (kernel-arguments '("console=ttyS0"))
131 (file-systems (cons (file-system
132 (device (file-system-label "my-root"))
136 (services (cons (service marionette-service-type
137 (marionette-configuration
138 (imported-modules '((gnu services herd)
139 (guix combinators)))))
142 (define (operating-system-with-current-guix os)
143 "Return a variant of OS that uses the current Guix."
146 (services (modify-services (operating-system-user-services os)
147 (guix-service-type config =>
150 (guix (current-guix))))))))
153 (define MiB (expt 2 20))
155 (define %simple-installation-script
156 ;; Shell script of a simple installation.
162 export GUIX_BUILD_OPTIONS=--no-grafts
164 parted --script /dev/vdb mklabel gpt \\
165 mkpart primary ext2 1M 3M \\
166 mkpart primary ext2 3M 1.4G \\
169 mkfs.ext4 -L my-root /dev/vdb2
172 herd start cow-store /mnt
174 cp /etc/target-config.scm /mnt/etc/config.scm
175 guix system init /mnt/etc/config.scm /mnt --no-substitutes
179 (define %extlinux-gpt-installation-script
180 ;; Shell script of a simple installation.
181 ;; As syslinux 6.0.3 does not handle 64bits ext4 partitions,
182 ;; we make sure to pass -O '^64bit' to mkfs.
188 export GUIX_BUILD_OPTIONS=--no-grafts
190 parted --script /dev/vdb mklabel gpt \\
191 mkpart ext2 1M 1.4G \\
193 mkfs.ext4 -L my-root -O '^64bit' /dev/vdb1
196 herd start cow-store /mnt
198 cp /etc/target-config.scm /mnt/etc/config.scm
199 guix system init /mnt/etc/config.scm /mnt --no-substitutes
203 (define* (run-install target-os target-os-source
205 (script %simple-installation-script)
208 (os (marionette-operating-system
210 ;; Since the image has no network access, use the
211 ;; current Guix so the store items we need are in
212 ;; the image and add packages provided.
213 (inherit (operating-system-add-packages
214 (operating-system-with-current-guix
217 (kernel-arguments '("console=ttyS0")))
218 #:imported-modules '((gnu services herd)
219 (gnu installer tests)
220 (guix combinators))))
221 (installation-disk-image-file-system-type "ext4")
222 (install-size 'guess)
223 (target-size (* 2200 MiB)))
224 "Run SCRIPT (a shell script following the system installation procedure) in
225 OS to install TARGET-OS. Return a VM image of TARGET-SIZE bytes containing
226 the installed system. The packages specified in PACKAGES will be appended to
227 packages defined in installation-os."
229 (mlet* %store-monad ((_ (set-grafting #f))
230 (system (current-system))
231 (target (current-target-system))
232 (base-image -> (find-image
233 installation-disk-image-file-system-type
236 ;; Since the installation system has no network access,
237 ;; we cheat a little bit by adding TARGET to its GC
238 ;; roots. This way, we know 'guix system init' will
239 ;; succeed. Also add guile-final, which is pulled in
240 ;; through provenance.drv and may not always be present.
241 (target (operating-system-derivation target-os))
248 (operating-system-with-gc-roots
249 os (list target guile-final)))
250 ;; Don't provide substitutes; too big.
251 (substitutable? #f)))))
253 (with-imported-modules '((guix build utils)
254 (gnu build marionette))
256 (use-modules (guix build utils)
257 (gnu build marionette))
259 (set-path-environment-variable "PATH" '("bin")
260 (list #$qemu-minimal))
262 (system* "qemu-img" "create" "-f" "qcow2"
263 #$output #$(number->string target-size))
267 `(,(which #$(qemu-command system))
271 ((string=? "ext4" installation-disk-image-file-system-type)
273 ,(string-append "file=" #$image
274 ",if=virtio,readonly")))
275 ((string=? "iso9660" installation-disk-image-file-system-type)
276 #~("-cdrom" #$image))
279 "unsupported installation-disk-image-file-system-type:"
280 installation-disk-image-file-system-type)))
282 ,(string-append "file=" #$output ",if=virtio")
283 ,@(if (file-exists? "/dev/kvm")
287 (pk 'uname (marionette-eval '(uname) marionette))
290 (marionette-eval '(begin
291 (use-modules (gnu services herd))
295 (when #$(->bool script)
296 (marionette-eval '(call-with-output-file "/etc/target-config.scm"
298 (write '#$target-os-source port)))
301 ;; Run SCRIPT. It typically invokes 'reboot' as a last step and
302 ;; thus normally gets killed with SIGTERM by PID 1.
303 (let ((status (marionette-eval '(system #$script) marionette)))
304 (exit (or (equal? (status:term-sig status) SIGTERM)
305 (equal? (status:exit-val status) 0)))))
307 (when #$(->bool gui-test)
308 (wait-for-unix-socket "/var/guix/installer-socket"
310 (format #t "installer socket ready~%")
312 (exit #$(and gui-test
313 (gui-test #~marionette)))))))
315 (gexp->derivation "installation" install
316 #:substitutable? #f))) ;too big
318 (define* (qemu-command/writable-image image #:key (memory-size 256))
319 "Return as a monadic value the command to run QEMU on a writable copy of
320 IMAGE, a disk image. The QEMU VM has access to MEMORY-SIZE MiB of RAM."
321 (mlet %store-monad ((system (current-system)))
322 (return #~(let ((image #$image))
323 ;; First we need a writable copy of the image.
324 (format #t "creating writable image from '~a'...~%" image)
325 (unless (zero? (system* #+(file-append qemu-minimal
327 "create" "-f" "qcow2"
329 (string-append "backing_file=" image)
331 (error "failed to create writable QEMU image" image))
333 (chmod "disk.img" #o644)
334 `(,(string-append #$qemu-minimal "/bin/"
335 #$(qemu-command system))
336 ,@(if (file-exists? "/dev/kvm")
339 "-no-reboot" "-m" #$(number->string memory-size)
340 "-drive" "file=disk.img,if=virtio")))))
342 (define %test-installed-os
344 (name "installed-os")
346 "Test basic functionality of an OS installed like one would do by hand.
347 This test is expensive in terms of CPU and storage usage since we need to
348 build (current-guix) and then store a couple of full system images.")
350 (mlet* %store-monad ((image (run-install %minimal-os %minimal-os-source))
351 (command (qemu-command/writable-image image)))
352 (run-basic-test %minimal-os command
355 (define %test-installed-extlinux-os
357 (name "installed-extlinux-os")
359 "Test basic functionality of an OS booted with an extlinux bootloader. As
360 per %test-installed-os, this test is expensive in terms of CPU and storage.")
362 (mlet* %store-monad ((image (run-install %minimal-extlinux-os
363 %minimal-extlinux-os-source
367 %extlinux-gpt-installation-script))
368 (command (qemu-command/writable-image image)))
369 (run-basic-test %minimal-extlinux-os command
370 "installed-extlinux-os")))))
374 ;;; Installation through an ISO image.
377 (define-os-with-source (%minimal-os-on-vda %minimal-os-on-vda-source)
378 ;; The OS we want to install.
379 (use-modules (gnu) (gnu tests) (srfi srfi-1))
382 (host-name "liberigilo")
383 (timezone "Europe/Paris")
384 (locale "en_US.UTF-8")
386 (bootloader (bootloader-configuration
387 (bootloader grub-bootloader)
388 (target "/dev/vda")))
389 (kernel-arguments '("console=ttyS0"))
390 (file-systems (cons (file-system
391 (device (file-system-label "my-root"))
395 (users (cons (user-account
397 (comment "Bob's sister")
399 (supplementary-groups '("wheel" "audio" "video")))
400 %base-user-accounts))
401 (services (cons (service marionette-service-type
402 (marionette-configuration
403 (imported-modules '((gnu services herd)
405 (guix combinators)))))
408 (define %simple-installation-script-for-/dev/vda
409 ;; Shell script of a simple installation.
415 export GUIX_BUILD_OPTIONS=--no-grafts
417 parted --script /dev/vda mklabel gpt \\
418 mkpart primary ext2 1M 3M \\
419 mkpart primary ext2 3M 1.4G \\
422 mkfs.ext4 -L my-root /dev/vda2
425 herd start cow-store /mnt
427 cp /etc/target-config.scm /mnt/etc/config.scm
428 guix system init /mnt/etc/config.scm /mnt --no-substitutes
432 (define %test-iso-image-installer
434 (name "iso-image-installer")
438 (mlet* %store-monad ((image (run-install
440 %minimal-os-on-vda-source
442 %simple-installation-script-for-/dev/vda
443 #:installation-disk-image-file-system-type
445 (command (qemu-command/writable-image image)))
446 (run-basic-test %minimal-os-on-vda command name)))))
453 (define-os-with-source (%separate-home-os %separate-home-os-source)
454 ;; The OS we want to install.
455 (use-modules (gnu) (gnu tests) (srfi srfi-1))
458 (host-name "liberigilo")
459 (timezone "Europe/Paris")
460 (locale "en_US.utf8")
462 (bootloader (bootloader-configuration
463 (bootloader grub-bootloader)
464 (target "/dev/vdb")))
465 (kernel-arguments '("console=ttyS0"))
466 (file-systems (cons* (file-system
467 (device (file-system-label "my-root"))
472 (mount-point "/home")
475 (users (cons* (user-account
481 %base-user-accounts))
482 (services (cons (service marionette-service-type
483 (marionette-configuration
484 (imported-modules '((gnu services herd)
485 (guix combinators)))))
488 (define %test-separate-home-os
490 (name "separate-home-os")
492 "Test basic functionality of an installed OS with a separate /home
493 partition. In particular, home directories must be correctly created (see
494 <https://bugs.gnu.org/21108>).")
496 (mlet* %store-monad ((image (run-install %separate-home-os
497 %separate-home-os-source
499 %simple-installation-script))
500 (command (qemu-command/writable-image image)))
501 (run-basic-test %separate-home-os command "separate-home-os")))))
505 ;;; Separate /gnu/store partition.
508 (define-os-with-source (%separate-store-os %separate-store-os-source)
509 ;; The OS we want to install.
510 (use-modules (gnu) (gnu tests) (srfi srfi-1))
513 (host-name "liberigilo")
514 (timezone "Europe/Paris")
515 (locale "en_US.UTF-8")
517 (bootloader (bootloader-configuration
518 (bootloader grub-bootloader)
519 (target "/dev/vdb")))
520 (kernel-arguments '("console=ttyS0"))
521 (file-systems (cons* (file-system
522 (device (file-system-label "root-fs"))
526 (device (file-system-label "store-fs"))
530 (users %base-user-accounts)
531 (services (cons (service marionette-service-type
532 (marionette-configuration
533 (imported-modules '((gnu services herd)
534 (guix combinators)))))
537 (define %separate-store-installation-script
538 ;; Installation with a separate /gnu partition.
544 export GUIX_BUILD_OPTIONS=--no-grafts
546 parted --script /dev/vdb mklabel gpt \\
547 mkpart primary ext2 1M 3M \\
548 mkpart primary ext2 3M 400M \\
549 mkpart primary ext2 400M 2.1G \\
552 mkfs.ext4 -L root-fs /dev/vdb2
553 mkfs.ext4 -L store-fs /dev/vdb3
556 mount /dev/vdb3 /mnt/gnu
559 herd start cow-store /mnt
561 cp /etc/target-config.scm /mnt/etc/config.scm
562 guix system init /mnt/etc/config.scm /mnt --no-substitutes
566 (define %test-separate-store-os
568 (name "separate-store-os")
570 "Test basic functionality of an OS installed like one would do by hand,
571 where /gnu lives on a separate partition.")
573 (mlet* %store-monad ((image (run-install %separate-store-os
574 %separate-store-os-source
576 %separate-store-installation-script))
577 (command (qemu-command/writable-image image)))
578 (run-basic-test %separate-store-os command "separate-store-os")))))
582 ;;; RAID root device.
585 (define-os-with-source (%raid-root-os %raid-root-os-source)
586 ;; An OS whose root partition is a RAID partition.
587 (use-modules (gnu) (gnu tests))
590 (host-name "raidified")
591 (timezone "Europe/Paris")
592 (locale "en_US.utf8")
594 (bootloader (bootloader-configuration
595 (bootloader grub-bootloader)
596 (target "/dev/vdb")))
597 (kernel-arguments '("console=ttyS0"))
599 ;; Add a kernel module for RAID-1 (aka. "mirror").
600 (initrd-modules (cons "raid1" %base-initrd-modules))
602 (mapped-devices (list (mapped-device
603 (source (list "/dev/vda2" "/dev/vda3"))
605 (type raid-device-mapping))))
606 (file-systems (cons (file-system
607 (device (file-system-label "root-fs"))
610 (dependencies mapped-devices))
612 (users %base-user-accounts)
613 (services (cons (service marionette-service-type
614 (marionette-configuration
615 (imported-modules '((gnu services herd)
616 (guix combinators)))))
619 (define %raid-root-installation-script
620 ;; Installation with a separate /gnu partition. See
621 ;; <https://raid.wiki.kernel.org/index.php/RAID_setup> for more on RAID and
628 export GUIX_BUILD_OPTIONS=--no-grafts
629 parted --script /dev/vdb mklabel gpt \\
630 mkpart primary ext2 1M 3M \\
631 mkpart primary ext2 3M 1.4G \\
632 mkpart primary ext2 1.4G 2.8G \\
635 yes | mdadm --create /dev/md0 --verbose --level=mirror --raid-devices=2 \\
637 mkfs.ext4 -L root-fs /dev/md0
640 herd start cow-store /mnt
642 cp /etc/target-config.scm /mnt/etc/config.scm
643 guix system init /mnt/etc/config.scm /mnt --no-substitutes
647 (define %test-raid-root-os
649 (name "raid-root-os")
651 "Test functionality of an OS installed with a RAID root partition managed
654 (mlet* %store-monad ((image (run-install %raid-root-os
657 %raid-root-installation-script
658 #:target-size (* 2800 MiB)))
659 (command (qemu-command/writable-image image)))
660 (run-basic-test %raid-root-os
661 `(,@command) "raid-root-os")))))
665 ;;; LUKS-encrypted root file system.
668 (define-os-with-source (%encrypted-root-os %encrypted-root-os-source)
669 ;; The OS we want to install.
670 (use-modules (gnu) (gnu tests) (srfi srfi-1))
673 (host-name "liberigilo")
674 (timezone "Europe/Paris")
675 (locale "en_US.UTF-8")
677 (bootloader (bootloader-configuration
678 (bootloader grub-bootloader)
679 (target "/dev/vdb")))
681 ;; Note: Do not pass "console=ttyS0" so we can use our passphrase prompt
682 ;; detection logic in 'enter-luks-passphrase'.
684 (mapped-devices (list (mapped-device
685 (source (uuid "12345678-1234-1234-1234-123456789abc"))
686 (target "the-root-device")
687 (type luks-device-mapping))))
688 (file-systems (cons (file-system
689 (device "/dev/mapper/the-root-device")
693 (users (cons (user-account
696 (supplementary-groups '("wheel" "audio" "video")))
697 %base-user-accounts))
698 (services (cons (service marionette-service-type
699 (marionette-configuration
700 (imported-modules '((gnu services herd)
701 (guix combinators)))))
704 (define %luks-passphrase
705 ;; LUKS encryption passphrase used in tests.
708 (define %encrypted-root-installation-script
709 ;; Shell script of a simple installation.
715 export GUIX_BUILD_OPTIONS=--no-grafts
716 ls -l /run/current-system/gc-roots
717 parted --script /dev/vdb mklabel gpt \\
718 mkpart primary ext2 1M 3M \\
719 mkpart primary ext2 3M 1.4G \\
722 echo -n " %luks-passphrase " | \\
723 cryptsetup luksFormat --uuid=12345678-1234-1234-1234-123456789abc -q /dev/vdb2 -
724 echo -n " %luks-passphrase " | \\
725 cryptsetup open --type luks --key-file - /dev/vdb2 the-root-device
726 mkfs.ext4 -L my-root /dev/mapper/the-root-device
727 mount LABEL=my-root /mnt
728 herd start cow-store /mnt
730 cp /etc/target-config.scm /mnt/etc/config.scm
731 guix system build /mnt/etc/config.scm
732 guix system init /mnt/etc/config.scm /mnt --no-substitutes
736 (define (enter-luks-passphrase marionette)
737 "Return a gexp to be inserted in the basic system test running on MARIONETTE
738 to enter the LUKS passphrase."
739 (let ((ocrad (file-append ocrad "/bin/ocrad")))
741 (define (passphrase-prompt? text)
742 (string-contains (pk 'screen-text text) "Enter pass"))
744 (define (bios-boot-screen? text)
745 ;; Return true if TEXT corresponds to the boot screen, before GRUB's
747 (string-prefix? "SeaBIOS" text))
749 (test-assert "enter LUKS passphrase for GRUB"
751 ;; At this point we have no choice but to use OCR to determine
752 ;; when the passphrase should be entered.
753 (wait-for-screen-text #$marionette passphrase-prompt?
755 (marionette-type #$(string-append %luks-passphrase "\n")
758 ;; Now wait until we leave the boot screen. This is necessary so
759 ;; we can then be sure we match the "Enter passphrase" prompt from
760 ;; 'cryptsetup', in the initrd.
761 (wait-for-screen-text #$marionette (negate bios-boot-screen?)
765 (test-assert "enter LUKS passphrase for the initrd"
767 ;; XXX: Here we use OCR as well but we could instead use QEMU
768 ;; '-serial stdio' and run it in an input pipe,
769 (wait-for-screen-text #$marionette passphrase-prompt?
772 (marionette-type #$(string-append %luks-passphrase "\n")
775 ;; Take a screenshot for debugging purposes.
776 (marionette-control (string-append "screendump " #$output
777 "/post-initrd-passphrase.ppm")
780 (define %test-encrypted-root-os
782 (name "encrypted-root-os")
784 "Test basic functionality of an OS installed like one would do by hand.
785 This test is expensive in terms of CPU and storage usage since we need to
786 build (current-guix) and then store a couple of full system images.")
788 (mlet* %store-monad ((image (run-install %encrypted-root-os
789 %encrypted-root-os-source
791 %encrypted-root-installation-script))
792 (command (qemu-command/writable-image image)))
793 (run-basic-test %encrypted-root-os command "encrypted-root-os"
794 #:initialization enter-luks-passphrase)))))
798 ;;; Btrfs root file system.
801 (define-os-with-source (%btrfs-root-os %btrfs-root-os-source)
802 ;; The OS we want to install.
803 (use-modules (gnu) (gnu tests) (srfi srfi-1))
806 (host-name "liberigilo")
807 (timezone "Europe/Paris")
808 (locale "en_US.UTF-8")
810 (bootloader (bootloader-configuration
811 (bootloader grub-bootloader)
812 (target "/dev/vdb")))
813 (kernel-arguments '("console=ttyS0"))
814 (file-systems (cons (file-system
815 (device (file-system-label "my-root"))
819 (users (cons (user-account
822 (supplementary-groups '("wheel" "audio" "video")))
823 %base-user-accounts))
824 (services (cons (service marionette-service-type
825 (marionette-configuration
826 (imported-modules '((gnu services herd)
827 (guix combinators)))))
830 (define %btrfs-root-installation-script
831 ;; Shell script of a simple installation.
837 export GUIX_BUILD_OPTIONS=--no-grafts
838 ls -l /run/current-system/gc-roots
839 parted --script /dev/vdb mklabel gpt \\
840 mkpart primary ext2 1M 3M \\
841 mkpart primary ext2 3M 2G \\
844 mkfs.btrfs -L my-root /dev/vdb2
846 btrfs subvolume create /mnt/home
847 herd start cow-store /mnt
849 cp /etc/target-config.scm /mnt/etc/config.scm
850 guix system build /mnt/etc/config.scm
851 guix system init /mnt/etc/config.scm /mnt --no-substitutes
855 (define %test-btrfs-root-os
857 (name "btrfs-root-os")
859 "Test basic functionality of an OS installed like one would do by hand.
860 This test is expensive in terms of CPU and storage usage since we need to
861 build (current-guix) and then store a couple of full system images.")
863 (mlet* %store-monad ((image (run-install %btrfs-root-os
864 %btrfs-root-os-source
866 %btrfs-root-installation-script))
867 (command (qemu-command/writable-image image)))
868 (run-basic-test %btrfs-root-os command "btrfs-root-os")))))
872 ;;; Btrfs root file system on a subvolume.
875 (define-os-with-source (%btrfs-root-on-subvolume-os
876 %btrfs-root-on-subvolume-os-source)
877 ;; The OS we want to install.
878 (use-modules (gnu) (gnu tests) (srfi srfi-1))
882 (timezone "America/Montreal")
883 (locale "en_US.UTF-8")
884 (bootloader (bootloader-configuration
885 (bootloader grub-bootloader)
886 (target "/dev/vdb")))
887 (kernel-arguments '("console=ttyS0"))
888 (file-systems (cons* (file-system
889 (device (file-system-label "btrfs-pool"))
891 (options "subvol=rootfs,compress=zstd")
894 (device (file-system-label "btrfs-pool"))
895 (mount-point "/home")
896 (options "subvol=homefs,compress=lzo")
899 (users (cons (user-account
902 (supplementary-groups '("wheel" "audio" "video")))
903 %base-user-accounts))
904 (services (cons (service marionette-service-type
905 (marionette-configuration
906 (imported-modules '((gnu services herd)
907 (guix combinators)))))
910 (define %btrfs-root-on-subvolume-installation-script
911 ;; Shell script of a simple installation.
917 export GUIX_BUILD_OPTIONS=--no-grafts
918 ls -l /run/current-system/gc-roots
919 parted --script /dev/vdb mklabel gpt \\
920 mkpart primary ext2 1M 3M \\
921 mkpart primary ext2 3M 2G \\
925 # Setup the top level Btrfs file system with its subvolume.
926 mkfs.btrfs -L btrfs-pool /dev/vdb2
928 btrfs subvolume create /mnt/rootfs
929 btrfs subvolume create /mnt/homefs
932 # Mount the subvolumes, ready for installation.
933 mount LABEL=btrfs-pool -o 'subvol=rootfs,compress=zstd' /mnt
935 mount LABEL=btrfs-pool -o 'subvol=homefs,compress=zstd' /mnt/home
937 herd start cow-store /mnt
939 cp /etc/target-config.scm /mnt/etc/config.scm
940 guix system build /mnt/etc/config.scm
941 guix system init /mnt/etc/config.scm /mnt --no-substitutes
945 (define %test-btrfs-root-on-subvolume-os
947 (name "btrfs-root-on-subvolume-os")
949 "Test basic functionality of an OS installed like one would do by hand.
950 This test is expensive in terms of CPU and storage usage since we need to
951 build (current-guix) and then store a couple of full system images.")
955 (run-install %btrfs-root-on-subvolume-os
956 %btrfs-root-on-subvolume-os-source
958 %btrfs-root-on-subvolume-installation-script))
959 (command (qemu-command/writable-image image)))
960 (run-basic-test %btrfs-root-on-subvolume-os command
961 "btrfs-root-on-subvolume-os")))))
965 ;;; JFS root file system.
968 (define-os-with-source (%jfs-root-os %jfs-root-os-source)
969 ;; The OS we want to install.
970 (use-modules (gnu) (gnu tests) (srfi srfi-1))
973 (host-name "liberigilo")
974 (timezone "Europe/Paris")
975 (locale "en_US.UTF-8")
977 (bootloader (bootloader-configuration
978 (bootloader grub-bootloader)
979 (target "/dev/vdb")))
980 (kernel-arguments '("console=ttyS0"))
981 (file-systems (cons (file-system
982 (device (file-system-label "my-root"))
986 (users (cons (user-account
989 (supplementary-groups '("wheel" "audio" "video")))
990 %base-user-accounts))
991 (services (cons (service marionette-service-type
992 (marionette-configuration
993 (imported-modules '((gnu services herd)
994 (guix combinators)))))
997 (define %jfs-root-installation-script
998 ;; Shell script of a simple installation.
1004 export GUIX_BUILD_OPTIONS=--no-grafts
1005 ls -l /run/current-system/gc-roots
1006 parted --script /dev/vdb mklabel gpt \\
1007 mkpart primary ext2 1M 3M \\
1008 mkpart primary ext2 3M 2G \\
1011 jfs_mkfs -L my-root -q /dev/vdb2
1012 mount /dev/vdb2 /mnt
1013 herd start cow-store /mnt
1015 cp /etc/target-config.scm /mnt/etc/config.scm
1016 guix system build /mnt/etc/config.scm
1017 guix system init /mnt/etc/config.scm /mnt --no-substitutes
1021 (define %test-jfs-root-os
1023 (name "jfs-root-os")
1025 "Test basic functionality of an OS installed like one would do by hand.
1026 This test is expensive in terms of CPU and storage usage since we need to
1027 build (current-guix) and then store a couple of full system images.")
1029 (mlet* %store-monad ((image (run-install %jfs-root-os
1032 %jfs-root-installation-script))
1033 (command (qemu-command/writable-image image)))
1034 (run-basic-test %jfs-root-os command "jfs-root-os")))))
1038 ;;; F2FS root file system.
1041 (define-os-with-source (%f2fs-root-os %f2fs-root-os-source)
1042 ;; The OS we want to install.
1043 (use-modules (gnu) (gnu tests) (srfi srfi-1))
1046 (host-name "liberigilo")
1047 (timezone "Europe/Paris")
1048 (locale "en_US.UTF-8")
1050 (bootloader (bootloader-configuration
1051 (bootloader grub-bootloader)
1052 (target "/dev/vdb")))
1053 (kernel-arguments '("console=ttyS0"))
1054 (file-systems (cons (file-system
1055 (device (file-system-label "my-root"))
1058 %base-file-systems))
1059 (users (cons (user-account
1062 (supplementary-groups '("wheel" "audio" "video")))
1063 %base-user-accounts))
1064 (services (cons (service marionette-service-type
1065 (marionette-configuration
1066 (imported-modules '((gnu services herd)
1067 (guix combinators)))))
1070 (define %f2fs-root-installation-script
1071 ;; Shell script of a simple installation.
1077 export GUIX_BUILD_OPTIONS=--no-grafts
1078 ls -l /run/current-system/gc-roots
1079 parted --script /dev/vdb mklabel gpt \\
1080 mkpart primary ext2 1M 3M \\
1081 mkpart primary ext2 3M 2G \\
1084 mkfs.f2fs -l my-root -q /dev/vdb2
1085 mount /dev/vdb2 /mnt
1086 herd start cow-store /mnt
1088 cp /etc/target-config.scm /mnt/etc/config.scm
1089 guix system build /mnt/etc/config.scm
1090 guix system init /mnt/etc/config.scm /mnt --no-substitutes
1094 (define %test-f2fs-root-os
1096 (name "f2fs-root-os")
1098 "Test basic functionality of an OS installed like one would do by hand.
1099 This test is expensive in terms of CPU and storage usage since we need to
1100 build (current-guix) and then store a couple of full system images.")
1102 (mlet* %store-monad ((image (run-install %f2fs-root-os
1103 %f2fs-root-os-source
1105 %f2fs-root-installation-script))
1106 (command (qemu-command/writable-image image)))
1107 (run-basic-test %f2fs-root-os command "f2fs-root-os")))))
1111 ;;; Installation through the graphical interface.
1114 (define %syslog-conf
1115 ;; Syslog configuration that dumps to /dev/console, so we can see the
1116 ;; installer's messages during the test.
1117 (computed-file "syslog.conf"
1119 (copy-file #$%default-syslog.conf #$output)
1120 (chmod #$output #o644)
1121 (let ((port (open-file #$output "a")))
1122 (display "\n*.info /dev/console\n" port)
1125 (define (operating-system-with-console-syslog os)
1126 "Return OS with a syslog service that writes to /dev/console."
1129 (services (modify-services (operating-system-user-services os)
1130 (syslog-service-type config
1132 (syslog-configuration
1134 (config-file %syslog-conf)))))))
1136 (define %root-password "foo")
1138 (define* (gui-test-program marionette
1143 (define (screenshot file)
1144 (marionette-control (string-append "screendump " file)
1147 (define-syntax-rule (marionette-eval* exp marionette)
1148 (or (marionette-eval exp marionette)
1149 (throw 'marionette-eval-failure 'exp)))
1151 (setvbuf (current-output-port) 'none)
1152 (setvbuf (current-error-port) 'none)
1154 (marionette-eval* '(use-modules (gnu installer tests))
1157 ;; Arrange so that 'converse' prints debugging output to the console.
1158 (marionette-eval* '(let ((console (open-output-file "/dev/console")))
1159 (setvbuf console 'none)
1160 (conversation-log-port console))
1163 ;; Tell the installer to not wait for the Connman "online" status.
1164 (marionette-eval* '(call-with-output-file "/tmp/installer-assume-online"
1168 ;; Run 'guix system init' with '--no-grafts', to cope with the lack of
1170 (marionette-eval* '(call-with-output-file
1171 "/tmp/installer-system-init-options"
1173 (write '("--no-grafts" "--no-substitutes")
1177 (marionette-eval* '(define installer-socket
1178 (open-installer-socket))
1180 (screenshot "installer-start.ppm")
1182 (marionette-eval* '(choose-locale+keyboard installer-socket)
1184 (screenshot "installer-locale.ppm")
1186 ;; Choose the host name that the "basic" test expects.
1187 (marionette-eval* '(enter-host-name+passwords installer-socket
1188 #:host-name "liberigilo"
1195 (screenshot "installer-services.ppm")
1197 (marionette-eval* '(choose-services installer-socket
1198 #:choose-desktop-environment?
1200 #:choose-network-service?
1203 (screenshot "installer-partitioning.ppm")
1205 (marionette-eval* '(choose-partitioning installer-socket
1206 #:encrypted? #$encrypted?
1207 #:passphrase #$%luks-passphrase)
1209 (screenshot "installer-run.ppm")
1211 (marionette-eval* '(conclude-installation installer-socket)
1217 (define %extra-packages
1218 ;; Packages needed when installing with an encrypted root.
1220 lvm2-static cryptsetup-static e2fsck/static
1223 (define installation-os-for-gui-tests
1224 ;; Operating system that contains all of %EXTRA-PACKAGES, needed for the
1225 ;; target OS, as well as syslog output redirected to the console so we can
1226 ;; see what the installer is up to.
1227 (marionette-operating-system
1229 (inherit (operating-system-with-console-syslog
1230 (operating-system-add-packages
1231 (operating-system-with-current-guix
1234 (kernel-arguments '("console=ttyS0")))
1235 #:imported-modules '((gnu services herd)
1236 (gnu installer tests)
1237 (guix combinators))))
1239 (define* (installation-target-os-for-gui-tests
1240 #:key (encrypted? #f))
1242 (inherit %minimal-os-on-vda)
1243 (users (append (list (user-account
1245 (comment "Bob's sister")
1247 (supplementary-groups
1248 '("wheel" "audio" "video")))
1251 (comment "Alice's brother")
1253 (supplementary-groups
1254 '("wheel" "audio" "video"))))
1255 %base-user-accounts))
1256 ;; The installer does not create a swap device in guided mode with
1257 ;; encryption support.
1258 (swap-devices (if encrypted? '() '("/dev/vda2")))
1259 (services (cons (service dhcp-client-service-type)
1260 (operating-system-user-services %minimal-os-on-vda)))))
1262 (define* (installation-target-desktop-os-for-gui-tests
1263 #:key (encrypted? #f))
1265 (inherit (installation-target-os-for-gui-tests
1266 #:encrypted? encrypted?))
1267 (keyboard-layout (keyboard-layout "us" "altgr-intl"))
1269 ;; Make sure that all the packages and services that may be used by the
1270 ;; graphical installer are available.
1272 (list openbox awesome i3-wm i3status
1273 dmenu st ratpoison xterm)
1277 (list (service gnome-desktop-service-type)
1278 (service xfce-desktop-service-type)
1279 (service mate-desktop-service-type)
1280 (service enlightenment-desktop-service-type)
1281 (set-xorg-configuration
1283 (keyboard-layout keyboard-layout)))
1284 (service marionette-service-type
1285 (marionette-configuration
1286 (imported-modules '((gnu services herd)
1288 (guix combinators))))))
1289 %desktop-services))))
1291 (define* (guided-installation-test name
1296 (install-size 'guess)
1297 (target-size (* 2200 MiB)))
1301 "Install an OS using the graphical installer and test it.")
1304 ((image (run-install target-os '(this is unused)
1306 #:os installation-os-for-gui-tests
1307 #:install-size install-size
1308 #:target-size target-size
1309 #:installation-disk-image-file-system-type
1312 (lambda (marionette)
1316 #:encrypted? encrypted?))))
1317 (command (qemu-command/writable-image image)))
1318 (run-basic-test target-os command name
1319 #:initialization (and encrypted? enter-luks-passphrase)
1320 #:root-password %root-password)))))
1322 (define %test-gui-installed-os
1323 (guided-installation-test
1325 #:target-os (installation-target-os-for-gui-tests)))
1327 (define %test-gui-installed-os-encrypted
1328 (guided-installation-test
1329 "gui-installed-os-encrypted"
1331 #:target-os (installation-target-os-for-gui-tests
1334 ;; Building a desktop image is very time and space consuming. Install all
1335 ;; desktop environments in a single test to reduce the overhead.
1336 (define %test-gui-installed-desktop-os-encrypted
1337 (guided-installation-test "gui-installed-desktop-os-encrypted"
1341 (installation-target-desktop-os-for-gui-tests
1343 ;; XXX: The disk-image size guess is too low. Use
1344 ;; a constant value until this is fixed.
1345 #:install-size (* 8000 MiB)
1346 #:target-size (* 9000 MiB)))
1348 ;;; install.scm ends here