[PATCH 0/4] Test installation on Debian

  • Done
  • quality assurance status badge
Details
3 participants
  • Efraim Flashner
  • Ludovic Courtès
  • Rodion Goritskov
Owner
unassigned
Submitted by
Ludovic Courtès
Severity
normal
Blocked by

Debbugs page

Ludovic Courtès wrote 2 weeks ago
(address . guix-patches@gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
cover.1740243928.git.ludo@gnu.org
Hello Guix!

This series adds an automated test of ‘guix-install.sh’ on Debian,
which checks that “guix build hello” and “guix install hello” work
upon completion.

This was prompted by the work in https://issues.guix.gnu.org/75810
and by the upcoming (crossing fingers!) release.

It only tests Debian 12 but it should work with any systemd-based
distro that provides QCOW2 images.

Thoughts?

Ludo’.

Ludovic Courtès (4):
tests: Export ‘marionette-program’.
vm: ‘common-qemu-options’ splits command-line tokens.
vm: Export ‘file-system->mount-tag’ and ‘common-qemu-options’.
tests: Test installation on Debian.

gnu/local.mk | 1 +
gnu/system/vm.scm | 24 +--
gnu/tests.scm | 14 +-
gnu/tests/foreign.scm | 337 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 364 insertions(+), 12 deletions(-)
create mode 100644 gnu/tests/foreign.scm


base-commit: 256e623843a70b001801dcddd7acb4138e6216b4
--
2.48.1
Ludovic Courtès wrote 2 weeks ago
[PATCH 2/4] vm: ‘common-qemu-options’ splits command-line tokens.
(address . 76488@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
70d3a086aeed2da038467f6c4670e51b61f29cc6.1740243928.git.ludo@gnu.org
The result returned so far by ‘common-qemu-options’ assumed that it
would be passed to a shell. This is the case when using
‘system-qemu-image/shared-store-script’ but possibly not in other cases.

* gnu/system/vm.scm (common-qemu-options): Add #:image-format.
[virtfs-option]: Return a list of strings instead of a single
"-virtfs xyz" string. Update caller to use ‘append-map’.
Separate "-drive" string.

Change-Id: Ib07c27e2c4b2d222d7db2c612bb045d330bc7f68
---
gnu/system/vm.scm | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)

Toggle diff (50 lines)
diff --git a/gnu/system/vm.scm b/gnu/system/vm.scm
index 1e3f72c7b2a..dbfe873e4f5 100644
--- a/gnu/system/vm.scm
+++ b/gnu/system/vm.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013-2024 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013-2025 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2016 Christine Lemmer-Webber <cwebber@dustycloud.org>
;;; Copyright © 2016, 2017 Leo Famulari <leo@famulari.name>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
@@ -211,14 +211,16 @@ (define* (virtualized-operating-system os
(define* (common-qemu-options image shared-fs
#:key
+ (image-format "raw")
rw-image?
(target (%current-target-system)))
"Return the a string-value gexp with the common QEMU options to boot IMAGE,
with '-virtfs' options for the host file systems listed in SHARED-FS."
(define (virtfs-option fs)
- #~(format #f "-virtfs local,path=~s,security_model=none,mount_tag=~s"
- #$fs #$(file-system->mount-tag fs)))
+ #~("-virtfs"
+ (format #f "local,path=~a,security_model=none,mount_tag=~a"
+ #$fs #$(file-system->mount-tag fs))))
#~(;; Only enable kvm if we see /dev/kvm exists.
;; This allows users without hardware virtualization to still use these
@@ -230,11 +232,12 @@ (define* (common-qemu-options image shared-fs
"-object" "rng-random,filename=/dev/urandom,id=guix-vm-rng"
"-device" "virtio-rng-pci,rng=guix-vm-rng"
- #$@(map virtfs-option shared-fs)
- #$@(if rw-image?
- #~((format #f "-drive file=~a,format=qcow2,if=virtio" #$image))
- #~((format #f "-drive file=~a,format=raw,if=virtio,cache=writeback,werror=report,readonly=on"
- #$image)))))
+ #$@(append-map virtfs-option shared-fs)
+ "-drive"
+ #$(if rw-image?
+ #~(format #f "file=~a,format=qcow2,if=virtio" #$image)
+ #~(format #f "file=~a,format=~a,if=virtio,cache=writeback,werror=report,readonly=on"
+ #$image #$image-format))))
(define* (system-qemu-image/shared-store-script os
#:key
--
2.48.1
Ludovic Courtès wrote 2 weeks ago
[PATCH 3/4] vm: Export ‘file-system->mount- tag’ and ‘common-qemu-options’.
(address . 76488@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
ff123bd855481ab1c57e6d0d00678be00599a31c.1740243928.git.ludo@gnu.org
* gnu/system/vm.scm (file-system->mount-tag, common-qemu-options):
Export.

Change-Id: I7228e5c02f07f8c8633a64c86d9c81aa3cb2e8b7
---
gnu/system/vm.scm | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

Toggle diff (18 lines)
diff --git a/gnu/system/vm.scm b/gnu/system/vm.scm
index dbfe873e4f5..4f2a27daf7a 100644
--- a/gnu/system/vm.scm
+++ b/gnu/system/vm.scm
@@ -85,7 +85,10 @@ (define-module (gnu system vm)
virtual-machine-memory-size
virtual-machine-disk-image-size
virtual-machine-port-forwardings
- virtual-machine-date))
+ virtual-machine-date
+
+ file-system->mount-tag
+ common-qemu-options))
;;; Commentary:
--
2.48.1
Ludovic Courtès wrote 2 weeks ago
[PATCH 1/4] tests: Export ‘marionette-progr am’.
(address . 76488@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
5d7a1ecb87b871dc98c22be29041361bf543076a.1740243928.git.ludo@gnu.org
* gnu/tests.scm (%default-marionette-device): New variable.
(<marionette-configuration>)[device]: Use it.
(marionette-program): Make all parameters optional and export.

Change-Id: I496d88253b5ebad60da09a0cca5ed960aa2ab389
---
gnu/tests.scm | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)

Toggle diff (50 lines)
diff --git a/gnu/tests.scm b/gnu/tests.scm
index 2a9e51511f0..da0b0146ea7 100644
--- a/gnu/tests.scm
+++ b/gnu/tests.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2016-2020, 2022-2024 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2016-2020, 2022-2025 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2017 Tobias Geerinckx-Rice <me@tobias.gr>
;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
@@ -48,6 +48,7 @@ (define-module (gnu tests)
marionette-service-type
marionette-operating-system
+ marionette-program
define-os-with-source
%simple-os
@@ -72,11 +73,15 @@ (define-module (gnu tests)
;;;
;;; Code:
+(define %default-marionette-device
+ ;; Default marionette device in the guest.
+ "/dev/virtio-ports/org.gnu.guix.port.0")
+
(define-record-type* <marionette-configuration>
marionette-configuration make-marionette-configuration
marionette-configuration?
(device marionette-configuration-device ;string
- (default "/dev/virtio-ports/org.gnu.guix.port.0"))
+ (default %default-marionette-device))
(imported-modules marionette-configuration-imported-modules
(default '()))
(extensions marionette-configuration-extensions
@@ -92,7 +97,10 @@ (define-syntax-rule (with-imported-modules-and-extensions imported-modules
(with-extensions extensions
gexp)))
-(define (marionette-program device imported-modules extensions)
+(define* (marionette-program #:optional
+ (device %default-marionette-device)
+ (imported-modules '())
+ (extensions '()))
"Return the program that runs the marionette REPL on DEVICE. Ensure
IMPORTED-MODULES and EXTENSIONS are accessible from the REPL."
(define code
--
2.48.1
Ludovic Courtès wrote 2 weeks ago
[PATCH 4/4] tests: Test installation on Debian.
(address . 76488@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
ac27fc5a59300e05489bc3b76cca87cefb430913.1740243928.git.ludo@gnu.org
* gnu/tests/foreign.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add it.

Change-Id: I1f24d83bdc298acbef15db2e19775cc1d3fbd56c
---
gnu/local.mk | 1 +
gnu/tests/foreign.scm | 337 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 338 insertions(+)
create mode 100644 gnu/tests/foreign.scm

Toggle diff (357 lines)
diff --git a/gnu/local.mk b/gnu/local.mk
index c421da85cba..66cca59839e 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -848,6 +848,7 @@ GNU_SYSTEM_MODULES = \
%D%/tests/docker.scm \
%D%/tests/emacs.scm \
%D%/tests/file-sharing.scm \
+ %D%/tests/foreign.scm \
%D%/tests/ganeti.scm \
%D%/tests/gdm.scm \
%D%/tests/guix.scm \
diff --git a/gnu/tests/foreign.scm b/gnu/tests/foreign.scm
new file mode 100644
index 00000000000..8cf580cb22d
--- /dev/null
+++ b/gnu/tests/foreign.scm
@@ -0,0 +1,337 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2025 Ludovic Courtès <ludo@gnu.org>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu tests foreign)
+ #:use-module (guix download)
+ #:use-module (guix gexp)
+ #:use-module (guix modules)
+ #:use-module (guix monads)
+ #:use-module (guix packages)
+ #:use-module (guix profiles)
+ #:autoload (guix store) (%store-prefix %store-monad %graft?)
+ #:use-module (gnu compression)
+ #:use-module (gnu tests)
+ #:use-module (gnu packages base)
+ #:use-module (gnu packages bootstrap)
+ #:use-module (gnu packages guile)
+ #:use-module (gnu packages make-bootstrap)
+ #:use-module (gnu packages package-management)
+ #:use-module (gnu packages virtualization)
+ #:use-module (gnu system vm)
+ #:use-module ((guix scripts pack) #:prefix pack:)
+ #:use-module (srfi srfi-9))
+
+(define marionette-systemd-service
+ ;; Definition of the marionette service for systemd.
+ (plain-file "marionette.service" "
+[Unit]
+Description=Guix marionette service
+
+[Install]
+WantedBy=multi-user.target
+
+[Service]
+ExecStart=/opt/guix/bin/guile --no-auto-compile \\
+ /opt/guix/share/guix/marionette-repl.scm\n"))
+
+(define* (qcow-image-with-marionette image
+ #:key
+ (name "image-with-marionette.qcow2")
+ (device "/dev/vdb1"))
+ "Instrument IMAGE, returning a new image that contains a statically-linked
+Guile under /opt/guix and a marionette systemd service. The relevant file
+system is expected to be on DEVICE."
+ (define vm
+ (virtual-machine
+ (marionette-operating-system %simple-os)))
+
+ (define build
+ (with-imported-modules (source-module-closure
+ '((guix build utils)
+ (gnu build marionette)))
+ #~(begin
+ (use-modules (guix build utils)
+ (gnu build marionette))
+
+ (define target-image
+ #$output)
+
+ (invoke #+(file-append qemu "/bin/qemu-img")
+ "create" "-b" #$image
+ "-F" "qcow2" "-f" "qcow2" target-image
+ "10G")
+
+ ;; Run a VM that will mount IMAGE and populate it. This is somewhat
+ ;; more convenient to set up than 'guestfish' from libguestfs.
+ (let ((marionette
+ (make-marionette
+ (list #$vm "-drive"
+ (string-append "file=" target-image
+ ",format=qcow2,if=virtio,"
+ "cache=writeback,werror=report,readonly=off")))))
+
+ (marionette-eval '(system* "mount" #$device "/mnt")
+ marionette)
+ (marionette-eval '(system* "ls" "-la" "/mnt")
+ marionette)
+ (marionette-eval '(begin
+ (use-modules (guix build utils))
+ (mkdir-p "/mnt/opt/guix")
+ (copy-recursively #$%guile-static-initrd
+ "/mnt/opt/guix"
+ #:log (%make-void-port "w")))
+ marionette)
+ (marionette-eval '(system* "/mnt/opt/guix/bin/guile" "--version")
+ marionette)
+ (unless (= 42 (status:exit-val
+ (marionette-eval '(system* "/mnt/opt/guix/bin/guile"
+ "-c" "(exit 42)")
+ marionette)))
+ (error "statically-linked Guile is broken"))
+
+ ;; Install the marionette systemd service and activate it.
+ (marionette-eval '(begin
+ (mkdir-p "/mnt/opt/guix/share/guix")
+ (copy-file #$(marionette-program)
+ "/mnt/opt/guix/share/guix/marionette-repl.scm")
+
+ (mkdir-p "/mnt/etc/systemd/system")
+ (copy-file #$marionette-systemd-service
+ "/mnt/etc/systemd/system/marionette.service")
+
+ ;; Activate the service, as per 'systemctl
+ ;; enable marionette.service'.
+ (symlink
+ "/etc/systemd/system/marionette.service"
+ "/mnt/etc/systemd/system/multi-user.target.wants/marionette.service"))
+ marionette)
+
+ (unless (zero? (marionette-eval '(system* "umount" "/mnt")
+ marionette))
+ (error "failed to unmount device"))))))
+
+ (computed-file name build))
+
+(define (manifest-entry-without-grafts entry)
+ "Return ENTRY with grafts disabled on its contents."
+ (manifest-entry
+ (inherit entry)
+ (item (with-parameters ((%graft? #f))
+ (manifest-entry-item entry)))))
+
+(define %installation-tarball-manifest
+ ;; Manifest of the Guix installation tarball.
+ (concatenate-manifests
+ (list (packages->manifest (list guix))
+
+ ;; Include the dependencies of 'hello' in addition to 'guix' so that
+ ;; we can test 'guix build hello'.
+ (map-manifest-entries
+ manifest-entry-without-grafts
+ (package->development-manifest hello))
+
+ ;; Add the source of 'hello'.
+ (manifest
+ (list (manifest-entry
+ (name "hello-source")
+ (version (package-version hello))
+ (item (let ((file (origin-actual-file-name
+ (package-source hello))))
+ (computed-file
+ "hello-source"
+ #~(begin
+ ;; Put the tarball in a subdirectory since
+ ;; profile union crashes otherwise.
+ (mkdir #$output)
+ (mkdir (in-vicinity #$output "src"))
+ (symlink #$(package-source hello)
+ (in-vicinity #$output
+ (string-append "src/"
+ #$file))))))))))
+
+ ;; Include 'guile-final', which is needed when building derivations
+ ;; such as that of 'hello' but missing from the development manifest.
+ ;; Add '%bootstrap-guile', used by 'guix install --bootstrap'.
+ (map-manifest-entries
+ manifest-entry-without-grafts
+ (packages->manifest (list (canonical-package guile-3.0)
+ %bootstrap-guile))))))
+
+(define %guix-install-script
+ ;; The 'guix-install.sh' script.
+ ;;
+ ;; To test local changes, replace the expression below with:
+ ;;
+ ;; (local-file "../../etc/guix-install.sh")
+ ;;
+ ;; This cannot be done unconditionally since that file does not exists in
+ ;; inferiors.
+ (file-append (package-source guix) "/etc/guix-install.sh"))
+
+(define (run-foreign-install-test image name)
+ "Run an installation of Guix in IMAGE, the QCOW2 image of a systemd-based
+GNU/Linux distro, and check that the installation is functional."
+ (define instrumented-image
+ (qcow-image-with-marionette image
+ #:name (string-append name ".qcow2")))
+
+ (define (test tarball)
+ (with-imported-modules (source-module-closure
+ '((gnu build marionette)
+ (gnu system file-systems)))
+ #~(begin
+ (use-modules (gnu build marionette)
+ (gnu system file-systems)
+ (srfi srfi-64)
+ (ice-9 match))
+
+ (define marionette
+ (make-marionette
+ (list (string-append #$qemu-minimal "/bin/" (qemu-command))
+ #$@(common-qemu-options instrumented-image
+ (list (%store-prefix))
+ #:image-format "qcow2"
+ #:rw-image? #t)
+ "-m" "512"
+ "-snapshot")))
+
+ (test-runner-current (system-test-runner #$output))
+ (test-begin "foreign-install")
+
+ (test-equal "marionette works"
+ "Linux"
+ (marionette-eval '(utsname:sysname (uname))
+ marionette))
+
+ (test-equal "mount host file store"
+ 0
+ (marionette-eval
+ '(begin
+ (mkdir "/host")
+ (system* "mount" "-t" "9p"
+ "-o" "trans=virtio,cache=loose,ro"
+ #$(file-system->mount-tag (%store-prefix))
+ "/host"))
+ marionette))
+
+ (test-assert "screenshot before"
+ (marionette-control (string-append "screendump " #$output
+ "/before-install.ppm")
+ marionette))
+
+ (test-assert "install fake dependencies"
+ ;; The installation script insists on checking for the
+ ;; availability of 'wget' and 'gpg' but does not actually use them
+ ;; when 'GUIX_BINARY_FILE_NAME' is set. Provide fake binaries.
+ (marionette-eval '(begin
+ (symlink "/bin/true" "/bin/wget")
+ (symlink "/bin/true" "/bin/gpg")
+ #t)
+ marionette))
+
+ (test-assert "run install script"
+ (marionette-eval '(system
+ (string-append
+ "yes '' | GUIX_BINARY_FILE_NAME="
+ (in-vicinity "/host"
+ (basename #$tarball))
+ " sh "
+ (in-vicinity
+ "/host"
+ (string-drop #$%guix-install-script
+ #$(string-length
+ (%store-prefix))))))
+ marionette))
+
+ (test-equal "hello not already built"
+ #f
+ ;; Check that the next test will really build 'hello'.
+ (marionette-eval '(file-exists?
+ #$(with-parameters ((%graft? #f))
+ hello))
+ marionette))
+
+ (test-equal "guix build hello"
+ 0
+ ;; Check that guix-daemon is up and running and that the build
+ ;; environment is properly set up (build users, etc.).
+ (marionette-eval '(system* "guix" "build" "hello" "--no-grafts")
+ marionette))
+
+ (test-assert "hello indeed built"
+ (marionette-eval '(file-exists?
+ #$(with-parameters ((%graft? #f))
+ hello))
+ marionette))
+
+ (test-equal "guix install hello"
+ 0
+ ;; Check that ~/.guix-profile & co. are properly created.
+ (marionette-eval '(let ((pw (getpwuid (getuid))))
+ (setenv "USER" (passwd:name pw))
+ (setenv "HOME" (pk 'home (passwd:dir pw)))
+ (system* "guix" "install" "hello"
+ "--no-grafts" "--bootstrap"))
+ marionette))
+
+ (test-equal "user profile created"
+ 0
+ (marionette-eval '(system "ls -lad ~/.guix-profile")
+ marionette))
+
+ (test-equal "hello"
+ 0
+ (marionette-eval '(system "~/.guix-profile/bin/hello")
+ marionette))
+
+ (test-assert "screenshot after"
+ (marionette-control (string-append "screendump " #$output
+ "/after-install.ppm")
+ marionette))
+
+ (test-end))))
+
+ (mlet* %store-monad ((profile (profile-derivation
+ %installation-tarball-manifest))
+ (tarball (pack:self-contained-tarball
+ "guix-binary" profile
+ #:compressor (lookup-compressor "zstd")
+ #:profile-name "current-guix"
+ #:localstatedir? #t)))
+ (gexp->derivation name (test tarball))))
+
+(define debian-12-qcow2
+ ;; Image taken from <https://www.debian.org/distrib/>.
+ ;; XXX: Those images are periodically removed from debian.org.
+ (origin
+ (uri
+ "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-nocloud-amd64.qcow2")
+ (method url-fetch)
+ (sha256
+ (base32
+ "06vlcq2dzgczlyp9lfkkdf3dgvfjp22lh5xz0mnl0bdgzq61sykb"))))
+
+(define %test-foreign-install
+ (system-test
+ (name "debian-install")
+ (description
+ "Test installation of Guix on Debian using the @file{guix-install.sh}
+script.")
+ (value (run-foreign-install-test debian-12-qcow2 name))))
+
+%test-foreign-install
--
2.48.1
Rodion Goritskov wrote 2 weeks ago
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 76488@debbugs.gnu.org)
878qpwmk5x.fsf@goritskov.com
Hi,

Ludovic Courtès <ludo@gnu.org> writes:

Toggle quote (9 lines)
> * gnu/tests/foreign.scm: New file.
> * gnu/local.mk (GNU_SYSTEM_MODULES): Add it.
>
> Change-Id: I1f24d83bdc298acbef15db2e19775cc1d3fbd56c
> ---
> gnu/local.mk | 1 +
> gnu/tests/foreign.scm | 337 ++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 338 insertions(+)

I got some questions on the test itself.

Toggle quote (25 lines)
> diff --git a/gnu/tests/foreign.scm b/gnu/tests/foreign.scm
> new file mode 100644
> index 00000000000..8cf580cb22d
> --- /dev/null
> +++ b/gnu/tests/foreign.scm
> +(define-module (gnu tests foreign)
> + #:use-module (guix download)
> + #:use-module (guix gexp)
> + #:use-module (guix modules)
> + #:use-module (guix monads)
> + #:use-module (guix packages)
> + #:use-module (guix profiles)
> + #:autoload (guix store) (%store-prefix %store-monad %graft?)
> + #:use-module (gnu compression)
> + #:use-module (gnu tests)
> + #:use-module (gnu packages base)
> + #:use-module (gnu packages bootstrap)
> + #:use-module (gnu packages guile)
> + #:use-module (gnu packages make-bootstrap)
> + #:use-module (gnu packages package-management)
> + #:use-module (gnu packages virtualization)
> + #:use-module (gnu system vm)
> + #:use-module ((guix scripts pack) #:prefix pack:)
> + #:use-module (srfi srfi-9))

How could I run this test?
As I see, the #:export is missing, so I couldn't run it with the make
check-system.
Sorry, I am kind of a newcomer to the Guile world - I see the call of
the %test-foreign-install in the end of the file, but how should I run
the whole file?

Toggle quote (4 lines)
> + (define vm
> + (virtual-machine
> + (marionette-operating-system %simple-os)))

Somehow I got some out of memory errors a couple of times during the
qcow build with this configuration
- so I changed to the following and stopped encountering this issue (odd
that 256 MB is not enough here sometimes):
Toggle quote (13 lines)
> (define vm
> (virtual-machine
> (operating-system (marionette-operating-system %simple-os))
> (memory-size 512)))


> + (marionette-eval '(begin
> + (use-modules (guix build utils))
> + (mkdir-p "/mnt/opt/guix")
> + (copy-recursively #$%guile-static-initrd
> + "/mnt/opt/guix"
> + #:log (%make-void-port "w")))

On this step I see, that guile reports that source files are newer than go
files and starts recompilation.
Probably, that is because of updated timestamps when copying.
Looks like it could be fixed with the keep-mtime? set to true.
Toggle quote (8 lines)
> (marionette-eval '(begin
> (use-modules (guix build utils))
> (mkdir-p "/mnt/opt/guix")
> (copy-recursively #$%guile-static-initrd
> "/mnt/opt/guix"
> #:log (%make-void-port "w")
> #:keep-mtime? #t))

After that test installs guix on debian, but during the build of
hello it starts building all the dependencies, which is unexpected, I
think, and fails during the fetching of sources (which is, probably,
expected, because the network is not available).

Sorry for the inconvenience, I still figuring out how it works (or
should work).
Ludovic Courtès wrote 2 weeks ago
(name . Rodion Goritskov)(address . rodion@goritskov.com)(address . 76488@debbugs.gnu.org)
87v7t0uxrr.fsf@gnu.org
Hi Rodion,

Rodion Goritskov <rodion@goritskov.com> skribis:

Toggle quote (7 lines)
> How could I run this test?
> As I see, the #:export is missing, so I couldn't run it with the make
> check-system.
> Sorry, I am kind of a newcomer to the Guile world - I see the call of
> the %test-foreign-install in the end of the file, but how should I run
> the whole file?

Oops, I ran it with:

./pre-inst-env guix build -f gnu/tests/foreign.scm

but really, it should have exported the test so one can run:

make check-system TESTS=debian-install

I’ll fix that in a second version.

Toggle quote (9 lines)
>> + (define vm
>> + (virtual-machine
>> + (marionette-operating-system %simple-os)))
>
> Somehow I got some out of memory errors a couple of times during the
> qcow build with this configuration
> - so I changed to the following and stopped encountering this issue (odd
> that 256 MB is not enough here sometimes):

Interesting; it worked for me. But perhaps that has to do with the
timestamp issue: if .scm files were being recompiled due to timestamps,
then the process ended up consuming more memory.

Toggle quote (12 lines)
>> + (marionette-eval '(begin
>> + (use-modules (guix build utils))
>> + (mkdir-p "/mnt/opt/guix")
>> + (copy-recursively #$%guile-static-initrd
>> + "/mnt/opt/guix"
>> + #:log (%make-void-port "w")))
>
> On this step I see, that guile reports that source files are newer than go
> files and starts recompilation.
> Probably, that is because of updated timestamps when copying.
> Looks like it could be fixed with the keep-mtime? set to true.

Yes, that’s a good idea. I guess I was just lucky the .scm timestamps
looked older than .go timestamps.

Toggle quote (5 lines)
> After that test installs guix on debian, but during the build of
> hello it starts building all the dependencies, which is unexpected, I
> think, and fails during the fetching of sources (which is, probably,
> expected, because the network is not available).

‘%installation-tarball-manifest’ is so that only ‘hello’ itself is
missing from the store. If you observe that it tries to build more,
then something is wrong; looking at the “The following derivations will
be built” message can (maybe) give a hint, by looking at the bottom of
that long derivation list.

Thanks for taking a look, I’ll send a new version fixing these issues!

Ludo’.
Efraim Flashner wrote 2 weeks ago
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 76488@debbugs.gnu.org)
Z7w8P4FdZOoBMrrG@3900XT
On Sat, Feb 22, 2025 at 06:10:16PM +0100, Ludovic Courtès wrote:
Toggle quote (13 lines)
> +
> +(define debian-12-qcow2
> + ;; Image taken from <https://www.debian.org/distrib/>.
> + ;; XXX: Those images are periodically removed from debian.org.
> + (origin
> + (uri
> + "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-nocloud-amd64.qcow2")
> + (method url-fetch)
> + (sha256
> + (base32
> + "06vlcq2dzgczlyp9lfkkdf3dgvfjp22lh5xz0mnl0bdgzq61sykb"))))
>

It would probably be better to use the direct URL

I have questions about also running the test on aarch64 or powerpc64le,
but that can be adjusted after the fact.

--
Efraim Flashner <efraim@flashner.co.il> אפרים פלשנר
GPG key = A28B F40C 3E55 1372 662D 14F7 41AA E7DC CA3D 8351
Confidentiality cannot be guaranteed on emails sent or received unencrypted
-----BEGIN PGP SIGNATURE-----

iQIzBAABCAAdFiEEoov0DD5VE3JmLRT3Qarn3Mo9g1EFAme8PDwACgkQQarn3Mo9
g1Gkww//QSWndYSCrrg/HfL8IzIlIwLVfmqHKoVaQQZa4C0muy6QF/SgfS1SHhAt
nm78aRFrJgho4UZjLmHI+sKDpMwf4o32zKKJpY0Hbf6TZso6Ex+O2jHHIu0jBI4x
OcyZjIGCmi7JyFQ31VecqOg/9t9nWgZZXeJ37IyE4l9ymWt3Og4b0wFZAZm0BoDP
S1JIYXvxh5Spe1lB0Xo7f043g8KKNkn9WxoVrUbgL1MJX/Bz5n9btt84drkuad/8
PtNgFsD+fAhEIXgzzzB3U02qtZvxMv9H+upCVR0l9N3KgSpYyhLpBvyoAC8H/4bo
aOiI0M0DdG+0ayo2K25EyAZFNG/1OCW5p1c5rr2S0uKLpWf/7ZXIcZQg69pwgSGf
z91UKrndxEetTh0WOxvvYkpQ19Al+jg6PtILOi43L277izzisVRESraRc3kJhB64
uetHkEilJ/2QgMjxrffayGXfzRL9xTy/zGGejHiGWjxV4d3LCockG/qxxVbBjngK
Ruj3Rrc/mDrpTq1e2OLnek7WV4AHviphMnMkXyCEok+Et8lR+IA3kA0zpyW2xYrL
BAnCc+WC7Q+Qb1hyKO79nIzcy2SIdm636Nzi53gDvuokKQMbYakPThfbYoKX9/kE
q2wtYhF6u7GlAunBoePzYXpedYUkjXwVPQ1lrGcfPR2u43NcKjk=
=5vTh
-----END PGP SIGNATURE-----


Ludovic Courtès wrote 2 weeks ago
(name . Rodion Goritskov)(address . rodion@goritskov.com)(address . 76488@debbugs.gnu.org)
87plj7slwe.fsf@gnu.org
Rodion Goritskov <rodion@goritskov.com> skribis:

Toggle quote (5 lines)
> After that test installs guix on debian, but during the build of
> hello it starts building all the dependencies, which is unexpected, I
> think, and fails during the fetching of sources (which is, probably,
> expected, because the network is not available).

Silly me: this patch series actually depends on
https://issues.guix.gnu.org/76485. That’s why you’re experiencing
this.

As a workaround, you can build with ‘--no-grafts’.

Ludo’.
Ludovic Courtès wrote 2 weeks ago
(name . Efraim Flashner)(address . efraim@flashner.co.il)(address . 76488@debbugs.gnu.org)
87ldtvslt6.fsf@gnu.org
Hello,

Efraim Flashner <efraim@flashner.co.il> skribis:

Toggle quote (3 lines)
> It would probably be better to use the direct URL
> https://cloud.debian.org/images/cloud/bookworm/20250210-2019/debian-12-nocloud-amd64-20250210-2019.qcow2

Will do!

Toggle quote (3 lines)
> I have questions about also running the test on aarch64 or powerpc64le,
> but that can be adjusted after the fact.

Right. I only focused on x86_64-linux here.

Thanks,
Ludo’.
Ludovic Courtès wrote 2 weeks ago
control message for bug #76488
(address . control@debbugs.gnu.org)
87jz9fslsj.fsf@gnu.org
block 76488 by 76485
quit
Ludovic Courtès wrote 2 weeks ago
[PATCH v2 0/4] Test installation on Debian
(address . 76488@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
cover.1740400981.git.ludo@gnu.org
Hi!

Changes in v2:

• Export ‘%test-debian-install’ as suggested by Rodion.

• Pass #:keep-mtime? #t to ‘copy-recursively’ as suggested by Rodion.

• Use “full” URL to Debian image as suggested by Efraim.

• Add test to check that the store is read-only.

• Add test running ‘guix install’ as an unprivileged user.

• Add test dumping /etc/os-release.

Feedback welcome!

Ludo’.

Ludovic Courtès (4):
tests: Export ‘marionette-program’.
vm: ‘common-qemu-options’ splits command-line tokens.
vm: Export ‘file-system->mount-tag’ and ‘common-qemu-options’.
tests: Test installation on Debian.

gnu/local.mk | 1 +
gnu/system/vm.scm | 24 ++-
gnu/tests.scm | 14 +-
gnu/tests/foreign.scm | 379 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 406 insertions(+), 12 deletions(-)
create mode 100644 gnu/tests/foreign.scm


base-commit: 256e623843a70b001801dcddd7acb4138e6216b4
--
2.48.1
Ludovic Courtès wrote 2 weeks ago
[PATCH v2 3/4] vm: Export ‘file-system->mou nt-tag’ and ‘common-qemu-options’.
(address . 76488@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
ff123bd855481ab1c57e6d0d00678be00599a31c.1740400981.git.ludo@gnu.org
* gnu/system/vm.scm (file-system->mount-tag, common-qemu-options):
Export.

Change-Id: I7228e5c02f07f8c8633a64c86d9c81aa3cb2e8b7
---
gnu/system/vm.scm | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

Toggle diff (18 lines)
diff --git a/gnu/system/vm.scm b/gnu/system/vm.scm
index dbfe873e4f5..4f2a27daf7a 100644
--- a/gnu/system/vm.scm
+++ b/gnu/system/vm.scm
@@ -85,7 +85,10 @@ (define-module (gnu system vm)
virtual-machine-memory-size
virtual-machine-disk-image-size
virtual-machine-port-forwardings
- virtual-machine-date))
+ virtual-machine-date
+
+ file-system->mount-tag
+ common-qemu-options))
;;; Commentary:
--
2.48.1
Ludovic Courtès wrote 2 weeks ago
[PATCH v2 2/4] vm: ‘common-qemu-options ’ splits command-line tokens.
(address . 76488@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
70d3a086aeed2da038467f6c4670e51b61f29cc6.1740400981.git.ludo@gnu.org
The result returned so far by ‘common-qemu-options’ assumed that it
would be passed to a shell. This is the case when using
‘system-qemu-image/shared-store-script’ but possibly not in other cases.

* gnu/system/vm.scm (common-qemu-options): Add #:image-format.
[virtfs-option]: Return a list of strings instead of a single
"-virtfs xyz" string. Update caller to use ‘append-map’.
Separate "-drive" string.

Change-Id: Ib07c27e2c4b2d222d7db2c612bb045d330bc7f68
---
gnu/system/vm.scm | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)

Toggle diff (50 lines)
diff --git a/gnu/system/vm.scm b/gnu/system/vm.scm
index 1e3f72c7b2a..dbfe873e4f5 100644
--- a/gnu/system/vm.scm
+++ b/gnu/system/vm.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013-2024 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013-2025 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2016 Christine Lemmer-Webber <cwebber@dustycloud.org>
;;; Copyright © 2016, 2017 Leo Famulari <leo@famulari.name>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
@@ -211,14 +211,16 @@ (define* (virtualized-operating-system os
(define* (common-qemu-options image shared-fs
#:key
+ (image-format "raw")
rw-image?
(target (%current-target-system)))
"Return the a string-value gexp with the common QEMU options to boot IMAGE,
with '-virtfs' options for the host file systems listed in SHARED-FS."
(define (virtfs-option fs)
- #~(format #f "-virtfs local,path=~s,security_model=none,mount_tag=~s"
- #$fs #$(file-system->mount-tag fs)))
+ #~("-virtfs"
+ (format #f "local,path=~a,security_model=none,mount_tag=~a"
+ #$fs #$(file-system->mount-tag fs))))
#~(;; Only enable kvm if we see /dev/kvm exists.
;; This allows users without hardware virtualization to still use these
@@ -230,11 +232,12 @@ (define* (common-qemu-options image shared-fs
"-object" "rng-random,filename=/dev/urandom,id=guix-vm-rng"
"-device" "virtio-rng-pci,rng=guix-vm-rng"
- #$@(map virtfs-option shared-fs)
- #$@(if rw-image?
- #~((format #f "-drive file=~a,format=qcow2,if=virtio" #$image))
- #~((format #f "-drive file=~a,format=raw,if=virtio,cache=writeback,werror=report,readonly=on"
- #$image)))))
+ #$@(append-map virtfs-option shared-fs)
+ "-drive"
+ #$(if rw-image?
+ #~(format #f "file=~a,format=qcow2,if=virtio" #$image)
+ #~(format #f "file=~a,format=~a,if=virtio,cache=writeback,werror=report,readonly=on"
+ #$image #$image-format))))
(define* (system-qemu-image/shared-store-script os
#:key
--
2.48.1
Ludovic Courtès wrote 2 weeks ago
[PATCH v2 1/4] tests: Export ‘marionette-pr ogram’.
(address . 76488@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
5d7a1ecb87b871dc98c22be29041361bf543076a.1740400981.git.ludo@gnu.org
* gnu/tests.scm (%default-marionette-device): New variable.
(<marionette-configuration>)[device]: Use it.
(marionette-program): Make all parameters optional and export.

Change-Id: I496d88253b5ebad60da09a0cca5ed960aa2ab389
---
gnu/tests.scm | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)

Toggle diff (50 lines)
diff --git a/gnu/tests.scm b/gnu/tests.scm
index 2a9e51511f0..da0b0146ea7 100644
--- a/gnu/tests.scm
+++ b/gnu/tests.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2016-2020, 2022-2024 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2016-2020, 2022-2025 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2017 Tobias Geerinckx-Rice <me@tobias.gr>
;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
@@ -48,6 +48,7 @@ (define-module (gnu tests)
marionette-service-type
marionette-operating-system
+ marionette-program
define-os-with-source
%simple-os
@@ -72,11 +73,15 @@ (define-module (gnu tests)
;;;
;;; Code:
+(define %default-marionette-device
+ ;; Default marionette device in the guest.
+ "/dev/virtio-ports/org.gnu.guix.port.0")
+
(define-record-type* <marionette-configuration>
marionette-configuration make-marionette-configuration
marionette-configuration?
(device marionette-configuration-device ;string
- (default "/dev/virtio-ports/org.gnu.guix.port.0"))
+ (default %default-marionette-device))
(imported-modules marionette-configuration-imported-modules
(default '()))
(extensions marionette-configuration-extensions
@@ -92,7 +97,10 @@ (define-syntax-rule (with-imported-modules-and-extensions imported-modules
(with-extensions extensions
gexp)))
-(define (marionette-program device imported-modules extensions)
+(define* (marionette-program #:optional
+ (device %default-marionette-device)
+ (imported-modules '())
+ (extensions '()))
"Return the program that runs the marionette REPL on DEVICE. Ensure
IMPORTED-MODULES and EXTENSIONS are accessible from the REPL."
(define code
--
2.48.1
Ludovic Courtès wrote 2 weeks ago
[PATCH v2 4/4] tests: Test installation on Debian.
(address . 76488@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
742467b923f62ae257eda4e32893a1d0b144e8f6.1740400981.git.ludo@gnu.org
* gnu/tests/foreign.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add it.

Change-Id: I1f24d83bdc298acbef15db2e19775cc1d3fbd56c
---
gnu/local.mk | 1 +
gnu/tests/foreign.scm | 379 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 380 insertions(+)
create mode 100644 gnu/tests/foreign.scm

Toggle diff (399 lines)
diff --git a/gnu/local.mk b/gnu/local.mk
index c421da85cba..66cca59839e 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -848,6 +848,7 @@ GNU_SYSTEM_MODULES = \
%D%/tests/docker.scm \
%D%/tests/emacs.scm \
%D%/tests/file-sharing.scm \
+ %D%/tests/foreign.scm \
%D%/tests/ganeti.scm \
%D%/tests/gdm.scm \
%D%/tests/guix.scm \
diff --git a/gnu/tests/foreign.scm b/gnu/tests/foreign.scm
new file mode 100644
index 00000000000..a08622424a7
--- /dev/null
+++ b/gnu/tests/foreign.scm
@@ -0,0 +1,379 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2025 Ludovic Courtès <ludo@gnu.org>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu tests foreign)
+ #:use-module (guix download)
+ #:use-module (guix gexp)
+ #:use-module (guix modules)
+ #:use-module (guix monads)
+ #:use-module (guix packages)
+ #:use-module (guix profiles)
+ #:autoload (guix store) (%store-prefix %store-monad %graft?)
+ #:use-module (gnu compression)
+ #:use-module (gnu tests)
+ #:use-module (gnu packages base)
+ #:use-module (gnu packages bootstrap)
+ #:use-module (gnu packages guile)
+ #:use-module (gnu packages make-bootstrap)
+ #:use-module (gnu packages package-management)
+ #:use-module (gnu packages virtualization)
+ #:use-module (gnu system vm)
+ #:use-module ((guix scripts pack) #:prefix pack:)
+ #:use-module (srfi srfi-9)
+ #:export (%test-debian-install))
+
+(define marionette-systemd-service
+ ;; Definition of the marionette service for systemd.
+ (plain-file "marionette.service" "
+[Unit]
+Description=Guix marionette service
+
+[Install]
+WantedBy=multi-user.target
+
+[Service]
+ExecStart=/opt/guix/bin/guile --no-auto-compile \\
+ /opt/guix/share/guix/marionette-repl.scm\n"))
+
+(define* (qcow-image-with-marionette image
+ #:key
+ (name "image-with-marionette.qcow2")
+ (device "/dev/vdb1"))
+ "Instrument IMAGE, returning a new image that contains a statically-linked
+Guile under /opt/guix and a marionette systemd service. The relevant file
+system is expected to be on DEVICE."
+ (define vm
+ (virtual-machine
+ (marionette-operating-system %simple-os)))
+
+ (define build
+ (with-imported-modules (source-module-closure
+ '((guix build utils)
+ (gnu build marionette)))
+ #~(begin
+ (use-modules (guix build utils)
+ (gnu build marionette))
+
+ (define target-image
+ #$output)
+
+ (invoke #+(file-append qemu "/bin/qemu-img")
+ "create" "-b" #$image
+ "-F" "qcow2" "-f" "qcow2" target-image
+ "10G")
+
+ ;; Run a VM that will mount IMAGE and populate it. This is somewhat
+ ;; more convenient to set up than 'guestfish' from libguestfs.
+ (let ((marionette
+ (make-marionette
+ (list #$vm "-drive"
+ (string-append "file=" target-image
+ ",format=qcow2,if=virtio,"
+ "cache=writeback,werror=report,readonly=off")))))
+
+ (marionette-eval '(system* "mount" #$device "/mnt")
+ marionette)
+ (marionette-eval '(system* "ls" "-la" "/mnt")
+ marionette)
+ (marionette-eval '(begin
+ (use-modules (guix build utils))
+ (mkdir-p "/mnt/opt/guix")
+ (copy-recursively #$%guile-static-initrd
+ "/mnt/opt/guix"
+ #:log (%make-void-port "w")
+ #:keep-mtime? #t))
+ marionette)
+ (marionette-eval '(system* "/mnt/opt/guix/bin/guile" "--version")
+ marionette)
+ (unless (= 42 (status:exit-val
+ (marionette-eval '(system* "/mnt/opt/guix/bin/guile"
+ "-c" "(exit 42)")
+ marionette)))
+ (error "statically-linked Guile is broken"))
+
+ ;; Install the marionette systemd service and activate it.
+ (marionette-eval '(begin
+ (mkdir-p "/mnt/opt/guix/share/guix")
+ (copy-file #$(marionette-program)
+ "/mnt/opt/guix/share/guix/marionette-repl.scm")
+
+ (mkdir-p "/mnt/etc/systemd/system")
+ (copy-file #$marionette-systemd-service
+ "/mnt/etc/systemd/system/marionette.service")
+
+ ;; Activate the service, as per 'systemctl
+ ;; enable marionette.service'.
+ (symlink
+ "/etc/systemd/system/marionette.service"
+ "/mnt/etc/systemd/system/multi-user.target.wants/marionette.service"))
+ marionette)
+
+ (unless (zero? (marionette-eval '(system* "umount" "/mnt")
+ marionette))
+ (error "failed to unmount device"))))))
+
+ (computed-file name build))
+
+(define (manifest-entry-without-grafts entry)
+ "Return ENTRY with grafts disabled on its contents."
+ (manifest-entry
+ (inherit entry)
+ (item (with-parameters ((%graft? #f))
+ (manifest-entry-item entry)))))
+
+(define %installation-tarball-manifest
+ ;; Manifest of the Guix installation tarball.
+ (concatenate-manifests
+ (list (packages->manifest (list guix))
+
+ ;; Include the dependencies of 'hello' in addition to 'guix' so that
+ ;; we can test 'guix build hello'.
+ (map-manifest-entries
+ manifest-entry-without-grafts
+ (package->development-manifest hello))
+
+ ;; Add the source of 'hello'.
+ (manifest
+ (list (manifest-entry
+ (name "hello-source")
+ (version (package-version hello))
+ (item (let ((file (origin-actual-file-name
+ (package-source hello))))
+ (computed-file
+ "hello-source"
+ #~(begin
+ ;; Put the tarball in a subdirectory since
+ ;; profile union crashes otherwise.
+ (mkdir #$output)
+ (mkdir (in-vicinity #$output "src"))
+ (symlink #$(package-source hello)
+ (in-vicinity #$output
+ (string-append "src/"
+ #$file))))))))))
+
+ ;; Include 'guile-final', which is needed when building derivations
+ ;; such as that of 'hello' but missing from the development manifest.
+ ;; Add '%bootstrap-guile', used by 'guix install --bootstrap'.
+ (map-manifest-entries
+ manifest-entry-without-grafts
+ (packages->manifest (list (canonical-package guile-3.0)
+ %bootstrap-guile))))))
+
+(define %guix-install-script
+ ;; The 'guix-install.sh' script.
+ ;;
+ ;; To test local changes, replace the expression below with:
+ ;;
+ ;; (local-file "../../etc/guix-install.sh")
+ ;;
+ ;; This cannot be done unconditionally since that file does not exists in
+ ;; inferiors.
+ (file-append (package-source guix) "/etc/guix-install.sh"))
+
+(define (run-foreign-install-test image name)
+ "Run an installation of Guix in IMAGE, the QCOW2 image of a systemd-based
+GNU/Linux distro, and check that the installation is functional."
+ (define instrumented-image
+ (qcow-image-with-marionette image
+ #:name (string-append name ".qcow2")))
+
+ (define (test tarball)
+ (with-imported-modules (source-module-closure
+ '((gnu build marionette)
+ (gnu system file-systems)))
+ #~(begin
+ (use-modules (gnu build marionette)
+ (gnu system file-systems)
+ (srfi srfi-64)
+ (ice-9 match))
+
+ (define marionette
+ (make-marionette
+ (list (string-append #$qemu-minimal "/bin/" (qemu-command))
+ #$@(common-qemu-options instrumented-image
+ (list (%store-prefix))
+ #:image-format "qcow2"
+ #:rw-image? #t)
+ "-m" "512"
+ "-snapshot")))
+
+ (test-runner-current (system-test-runner #$output))
+ (test-begin "foreign-install")
+
+ (test-equal "marionette works"
+ "Linux"
+ (marionette-eval '(utsname:sysname (uname))
+ marionette))
+
+ (test-assert "/etc/os-release"
+ (marionette-eval '(begin
+ (use-modules (ice-9 textual-ports))
+ (call-with-input-file "/etc/os-release"
+ get-string-all))
+ marionette))
+
+ (test-equal "mount host file store"
+ 0
+ (marionette-eval
+ '(begin
+ (mkdir "/host")
+ (system* "mount" "-t" "9p"
+ "-o" "trans=virtio,cache=loose,ro"
+ #$(file-system->mount-tag (%store-prefix))
+ "/host"))
+ marionette))
+
+ (test-assert "screenshot before"
+ (marionette-control (string-append "screendump " #$output
+ "/before-install.ppm")
+ marionette))
+
+ (test-assert "install fake dependencies"
+ ;; The installation script insists on checking for the
+ ;; availability of 'wget' and 'gpg' but does not actually use them
+ ;; when 'GUIX_BINARY_FILE_NAME' is set. Provide fake binaries.
+ (marionette-eval '(begin
+ (symlink "/bin/true" "/bin/wget")
+ (symlink "/bin/true" "/bin/gpg")
+ #t)
+ marionette))
+
+ (test-assert "run install script"
+ (marionette-eval '(system
+ (string-append
+ "yes '' | GUIX_BINARY_FILE_NAME="
+ (in-vicinity "/host"
+ (basename #$tarball))
+ " sh "
+ (in-vicinity
+ "/host"
+ (string-drop #$%guix-install-script
+ #$(string-length
+ (%store-prefix))))))
+ marionette))
+
+ (test-equal "hello not already built"
+ #f
+ ;; Check that the next test will really build 'hello'.
+ (marionette-eval '(file-exists?
+ #$(with-parameters ((%graft? #f))
+ hello))
+ marionette))
+
+ (test-equal "guix build hello"
+ 0
+ ;; Check that guix-daemon is up and running and that the build
+ ;; environment is properly set up (build users, etc.).
+ (marionette-eval '(system* "guix" "build" "hello" "--no-grafts")
+ marionette))
+
+ (test-assert "hello indeed built"
+ (marionette-eval '(file-exists?
+ #$(with-parameters ((%graft? #f))
+ hello))
+ marionette))
+
+ (test-equal "guix install hello"
+ 0
+ ;; Check that ~/.guix-profile & co. are properly created.
+ (marionette-eval '(let ((pw (getpwuid (getuid))))
+ (setenv "USER" (passwd:name pw))
+ (setenv "HOME" (pk 'home (passwd:dir pw)))
+ (system* "guix" "install" "hello"
+ "--no-grafts" "--bootstrap"))
+ marionette))
+
+ (test-equal "user profile created"
+ 0
+ (marionette-eval '(system "ls -lad ~/.guix-profile")
+ marionette))
+
+ (test-equal "hello"
+ 0
+ (marionette-eval '(system "~/.guix-profile/bin/hello")
+ marionette))
+
+ (test-equal "create user account"
+ 0
+ (marionette-eval '(system* "useradd" "-d" "/home/user" "-m"
+ "user")
+ marionette))
+
+ (test-equal "guix install hello, unprivileged user"
+ 0
+ ;; Check that 'guix' is in $PATH for new users and that
+ ;; ~user/.guix-profile also gets created.
+ (marionette-eval '(system "su - user -c \
+'guix install hello --no-grafts --bootstrap'")
+ marionette))
+
+ (test-equal "user hello"
+ 0
+ (marionette-eval '(system "~user/.guix-profile/bin/hello")
+ marionette))
+
+ (test-equal "unprivileged user profile created"
+ 0
+ (marionette-eval '(system "ls -lad ~user/.guix-profile")
+ marionette))
+
+ (test-equal "store is read-only"
+ EROFS
+ (marionette-eval '(catch 'system-error
+ (lambda ()
+ (mkdir (in-vicinity #$(%store-prefix)
+ "whatever"))
+ 0)
+ (lambda args
+ (system-error-errno args)))
+ marionette))
+
+ (test-assert "screenshot after"
+ (marionette-control (string-append "screendump " #$output
+ "/after-install.ppm")
+ marionette))
+
+ (test-end))))
+
+ (mlet* %store-monad ((profile (profile-derivation
+ %installation-tarball-manifest))
+ (tarball (pack:self-contained-tarball
+ "guix-binary" profile
+ #:compressor (lookup-compressor "zstd")
+ #:profile-name "current-guix"
+ #:localstatedir? #t)))
+ (gexp->derivation name (test tarball))))
+
+(define debian-12-qcow2
+ ;; Image taken from <https://www.debian.org/distrib/>.
+ ;; XXX: Those images are periodically removed from debian.org.
+ (origin
+ (uri
+ "https://cloud.debian.org/images/cloud/bookworm/20250210-2019/debian-12-nocloud-amd64-20250210-2019.qcow2")
+ (method url-fetch)
+ (sha256
+ (base32
+ "06vlcq2dzgczlyp9lfkkdf3dgvfjp22lh5xz0mnl0bdgzq61sykb"))))
+
+(define %test-debian-install
+ (system-test
+ (name "debian-install")
+ (description
+ "Test installation of Guix on Debian using the @file{guix-install.sh}
+script.")
+ (value (run-foreign-install-test debian-12-qcow2 name))))
--
2.48.1
Ludovic Courtès wrote 2 weeks ago
Re: [bug#76488] [PATCH 4/4] tests: Test installation on Debian.
(name . Rodion Goritskov)(address . rodion@goritskov.com)(address . 76488@debbugs.gnu.org)
87h64jtsb6.fsf@gnu.org
Just sent v2 of this patch series.
Rodion Goritskov wrote 2 weeks ago
Re: [bug#76488] [PATCH v2 0/4] Test installation on Debian
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 76488@debbugs.gnu.org)
8734g18uek.fsf@goritskov.com
Hi!

Change set v2 looks good to me - applies, test runs and passes fine (with patch
76485 applied).

Test cases look sufficient too.

Thanks!
Ludovic Courtès wrote 1 weeks ago
(name . Rodion Goritskov)(address . rodion@goritskov.com)(address . 76488@debbugs.gnu.org)
87plj2tmbz.fsf@gnu.org
Hi Rodion,

Rodion Goritskov <rodion@goritskov.com> skribis:

Toggle quote (5 lines)
> Change set v2 looks good to me - applies, test runs and passes fine (with patch
> 76485 applied).
>
> Test cases look sufficient too.

Great, thanks for testing!

I’m now waiting for https://issues.guix.gnu.org/76485 to settle.

In the meantime, I sent a followup to this patch series:

Ludo’.
Ludovic Courtès wrote 1 weeks ago
control message for bug #76636
(address . control@debbugs.gnu.org)
87o6ymtmb2.fsf@gnu.org
block 76636 by 76488
quit
Ludovic Courtès wrote 4 days ago
Re: [bug#76488] [PATCH v2 0/4] Test installation on Debian
(name . Rodion Goritskov)(address . rodion@goritskov.com)(address . 76488-done@debbugs.gnu.org)
87plivxoba.fsf@gnu.org
Hi,

Ludovic Courtès <ludo@gnu.org> skribis:

Toggle quote (2 lines)
> I’m now waiting for https://issues.guix.gnu.org/76485 to settle.

Pushed as f57a660fc6c97d8324c7f36b84bec5234720fbb5.

Ludo’.
Closed
?
Your comment

Commenting via the web interface is currently disabled.

To comment on this conversation send an email to 76488@debbugs.gnu.org

To respond to this issue using the mumi CLI, first switch to it
mumi current 76488
Then, you may apply the latest patchset in this issue (with sign off)
mumi am -- -s
Or, compose a reply to this issue
mumi compose
Or, send patches to this issue
mumi send-email *.patch
You may also tag this issue. See list of standard tags. For example, to set the confirmed and easy tags
mumi command -t +confirmed -t +easy
Or, remove the moreinfo tag and set the help tag
mumi command -t -moreinfo -t +help