1 # GNU Guix --- Functional package management for GNU
2 # Copyright © 2015 David Thompson <davet@gnu.org>
3 # Copyright © 2022 John Kehayias <john.kehayias@protonmail.com>
5 # This file is part of GNU Guix.
7 # GNU Guix is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or (at
10 # your option) any later version.
12 # GNU Guix is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
21 # Test 'guix environment'.
26 guix environment
--version
28 if ! guile
-c '((@ (guix scripts environment) assert-container-features))'
30 # User containers are not supported; skip this test.
34 tmpdir
="t-guix-environment-$$"
35 trap 'rm -r "$tmpdir"' EXIT
39 # Make sure the exit value is preserved.
40 if guix environment
--container --ad-hoc --bootstrap guile-bootstrap \
41 -- guile
-c '(exit 42)'
48 # Try '--root' and '--profile'.
50 guix environment
-C --ad-hoc --bootstrap guile-bootstrap
-r "$root" -- guile
--version
51 guix environment
-C -p "$root" --bootstrap -- guile
--version
52 path1
=$
(guix environment
-C -p "$root" --bootstrap -- guile
-c '(display (getenv "PATH"))')
53 path2
=$
(guix environment
-C --ad-hoc --bootstrap guile-bootstrap
-- guile
-c '(display (getenv "PATH"))')
54 test "$path1" = "$path2"
56 # Make sure "localhost" resolves.
57 guix environment
--container --ad-hoc --bootstrap guile-bootstrap \
58 -- guile
-c '(exit (pair? (getaddrinfo "localhost" "80")))'
60 # We should get ECONNREFUSED, not ENETUNREACH, which would indicate that "lo"
62 guix environment
--container --ad-hoc --bootstrap guile-bootstrap \
63 -- guile
-c "(exit (= ECONNREFUSED
66 (let ((sock (socket AF_INET SOCK_STREAM 0)))
67 (connect sock AF_INET INADDR_LOOPBACK 12345)))
69 (pk 'errno (system-error-errno args))))))"
71 # Make sure '--preserve' is honored.
72 result
="`FOOBAR=42; export FOOBAR; guix environment -C --ad-hoc --bootstrap \
73 guile-bootstrap -E ^FOO -- guile -c '(display (getenv \"FOOBAR\"))'`"
76 # By default, the UID inside the container should be the same as outside.
78 inner_uid
="`guix environment -C --ad-hoc --bootstrap guile-bootstrap \
79 -- guile -c '(display (getuid))'`"
80 test $inner_uid = $uid
82 # When '--user' is passed, the UID should be 1000. (Note: Use a separate HOME
83 # so that we don't run into problems when the test directory is under /home.)
85 inner_uid
="`HOME=$tmpdir guix environment -C --ad-hoc --bootstrap guile-bootstrap \
86 --user=gnu-guix -- guile -c '(display (getuid))'`"
87 test $inner_uid = 1000
89 if test "x$USER" = "x"; then USER
="`id -un`"; fi
91 # Check whether /etc/passwd and /etc/group are valid.
92 guix environment
-C --ad-hoc --bootstrap guile-bootstrap \
93 -- guile
-c "(exit (string=? \"$USER\" (passwd:name (getpwuid (getuid)))))"
94 guix environment
-C --ad-hoc --bootstrap guile-bootstrap \
95 -- guile
-c '(exit (string? (group:name (getgrgid (getgid)))))'
96 guix environment
-C --ad-hoc --bootstrap guile-bootstrap \
97 -- guile
-c '(use-modules (srfi srfi-1))
98 (exit (every group:name
99 (map getgrgid (vector->list (getgroups)))))'
101 # Make sure file-not-found errors in mounts are reported.
102 if guix environment
--container --ad-hoc --bootstrap guile-bootstrap \
103 --expose=/does-not-exist
-- guile
-c 1 2> "$tmpdir/error"
107 grep "/does-not-exist" "$tmpdir/error"
108 grep "[Nn]o such file" "$tmpdir/error"
111 # Make sure that the right directories are mapped.
113 (use-modules (ice-9 rdelim)
118 (filter-map (lambda (line)
119 (match (string-split line #\space)
122 ;; Ignore the root file system.
125 ;; Ignore these types of file systems, except if they
126 ;; correspond to a parent file system.
127 ((_ mount (or \"tmpfs\" \"proc\" \"sysfs\" \"devtmpfs\"
128 \"devpts\" \"cgroup\" \"mqueue\") _ _ _)
129 (and (string-prefix? (getcwd) mount)
133 (string-split (call-with-input-file \"/proc/mounts\" read-string)
136 (for-each (lambda (mount)
141 guix environment
--container --ad-hoc --bootstrap guile-bootstrap \
142 -- guile
-c "$mount_test_code" > $tmpdir/mounts
145 test `wc -l < $tmpdir/mounts` -eq 4
147 current_dir
="`cd $PWD; pwd -P`"
148 grep -e "$current_dir$" $tmpdir/mounts
# current directory
149 grep $
(guix build guile-bootstrap
) $tmpdir/mounts
150 grep -e "$NIX_STORE_DIR/.*-bash" $tmpdir/mounts
# bootstrap bash
154 # Make sure 'GUIX_ENVIRONMENT' is set to '~/.guix-profile' when requested
155 # within a container.
158 (exit (and (string=? (getenv "GUIX_ENVIRONMENT")
159 (string-append (getenv "HOME") "/.guix-profile"))
160 (string-prefix? "'"$NIX_STORE_DIR"'"
161 (readlink (string-append (getenv "HOME")
162 "/.guix-profile")))))'
165 && guix environment
--bootstrap --container --link-profile \
166 --ad-hoc guile-bootstrap
--pure \
167 -- guile
-c "$linktest"
170 # Test that user can be mocked.
171 usertest
='(exit (and (string=? (getenv "HOME") "/home/foognu")
172 (string=? (passwd:name (getpwuid 1000)) "foognu")
173 (file-exists? "/home/foognu/umock")))'
174 touch "$tmpdir/umock"
175 HOME
="$tmpdir" guix environment
--bootstrap --container --user=foognu \
176 --ad-hoc guile-bootstrap
--pure \
177 --share="$tmpdir/umock" \
178 -- guile
-c "$usertest"
180 # if not sharing CWD, chdir home
183 && guix environment
--bootstrap --container --no-cwd --user=foo \
184 --ad-hoc guile-bootstrap
--pure \
185 -- /bin
/sh
-c 'test $(pwd) == "/home/foo" -a ! -d '"$tmpdir"
188 # Check the exit code.
191 (use-modules (system foreign))
192 ;; Purposely make Guile crash with a segfault. :)
193 (pointer->string (make-pointer 123) 123)"
195 if guix environment
--bootstrap --container \
196 --ad-hoc guile-bootstrap
-- guile
-c "$abnormal_exit_code"
202 # Test the Filesystem Hierarchy Standard (FHS) container option, --emulate-fhs (-F)
204 # As this option requires a glibc package (glibc-for-fhs), try to run these
205 # tests with the user's global store to make it easier to build or download a
207 storedir
="`guile -c '(use-modules (guix config))(display %storedir)'`"
208 localstatedir
="`guile -c '(use-modules (guix config))(display %localstatedir)'`"
209 NIX_STORE_DIR
="$storedir"
210 GUIX_DAEMON_SOCKET
="$localstatedir/guix/daemon-socket/socket"
211 export NIX_STORE_DIR GUIX_DAEMON_SOCKET
213 if ! guile
-c '(use-modules (guix)) (exit (false-if-exception (open-connection)))'
218 # Test that the container has FHS specific files/directories. Note that /bin
219 # exists in a non-FHS container as it will contain sh, a symlink to the bash
220 # package, so we don't test for it.
221 guix shell
-C --emulate-fhs --bootstrap guile-bootstrap \
222 -- guile
-c '(exit (and (file-exists? "/etc/ld.so.cache")
223 (file-exists? "/lib")
224 (file-exists? "/sbin")
225 (file-exists? "/usr/bin")
226 (file-exists? "/usr/include")
227 (file-exists? "/usr/lib")
228 (file-exists? "/usr/libexec")
229 (file-exists? "/usr/sbin")
230 (file-exists? "/usr/share")))'
232 # Test that the ld cache was generated and can be successfully read.
233 guix shell
-CF --bootstrap guile-bootstrap \
234 -- guile
-c '(execlp "ldconfig" "ldconfig" "-p")'
236 # Test that the package glibc-for-fhs is in the container even if there is the
237 # regular glibc package from another source. See
238 # <https://issues.guix.gnu.org/58861>.
239 guix shell
-CF --bootstrap guile-bootstrap glibc \
240 -- guile
-c '(exit (if (string-contains (readlink "/lib/libc.so")
246 echo "TESTING SYMLINK IN CONTAINER"
247 guix shell
--bootstrap guile-bootstrap
--container \
248 --symlink=/usr
/bin
/guile
=bin
/guile
-- \
249 /usr
/bin
/guile
--version
251 # A dangling symlink causes the command to fail.
252 ! guix shell
--bootstrap -CS /usr
/bin
/python
=bin
/python guile-bootstrap
-- exit
254 # An invalid symlink spec causes the command to fail.
255 ! guix shell
--bootstrap -CS bin
/guile
=/usr
/bin
/guile guile-bootstrap
-- exit