epiphany w/ gtk4 and webkitgtk 2.38
[jackhill/guix/guix.git] / tests / guix-pack-relocatable.sh
index 358cac5..b90bc7f 100644 (file)
@@ -1,5 +1,6 @@
 # GNU Guix --- Functional package management for GNU
 # Copyright © 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+# Copyright © 2020 Eric Bavier <bavier@posteo.net>
 #
 # This file is part of GNU Guix.
 #
@@ -38,76 +39,210 @@ then
     exit 77
 fi
 
-STORE_PARENT="`dirname $NIX_STORE_DIR`"
-export STORE_PARENT
-if test "$STORE_PARENT" = "/"; then exit 77; fi
+# Attempt to run the given command in a namespace where the store is
+# invisible.  This makes sure the presence of the store does not hide
+# problems.
+run_without_store ()
+{
+    if unshare -r true         # Are user namespaces supported?
+    then
+       # Run that relocatable executable in a user namespace where we "erase"
+       # the store by mounting an empty file system on top of it.  That way,
+       # we exercise the wrapper code that creates the user namespace and
+       # bind-mounts the store.
+       unshare -mrf sh -c 'mount -t tmpfs -o ro none "$NIX_STORE_DIR"; '"$*"
+    else
+       # Run the relocatable program in the current namespaces.  This is a
+       # weak test because we're going to access store items from the host
+       # store.
+       sh -c "$*"
+    fi
+}
 
-if unshare -mrf sh -c 'mount -t tmpfs none "$STORE_PARENT"'
-then
-    # Test the wrapper that relies on user namespaces.
-    relocatable_option="-R"
-else
-    case "`uname -m`" in
-       x86_64|i?86)
-           # Test the wrapper that falls back to PRoot.
-           relocatable_option="-RR";;
-       *)
-           # XXX: Our 'proot' package currently fails tests on non-Intel
-           # architectures, so skip this by default.
-           exit 77;;
-    esac
-fi
+# Wait for the given file to show up.  Error out if it doesn't show up in a
+# timely fashion.
+wait_for_file ()
+{
+    i=0
+    while ! test -f "$1" && test $i -lt 20
+    do
+       sleep 0.3
+       i=`expr $i + 1`
+    done
+    test -f "$1"
+}
 
 test_directory="`mktemp -d`"
 export test_directory
 trap 'chmod -Rf +w "$test_directory"; rm -rf "$test_directory"' EXIT
 
-export relocatable_option
-tarball="`guix pack $relocatable_option -S /Bin=bin sed`"
-(cd "$test_directory"; tar xvf "$tarball")
-
-if unshare -r true             # Are user namespaces supported?
+if unshare -r true
 then
-    # Run that relocatable 'sed' in a user namespace where we "erase" the store by
-    # mounting an empty file system on top of it.  That way, we exercise the
-    # wrapper code that creates the user namespace and bind-mounts the store.
-    unshare -mrf sh -c 'mount -t tmpfs none "$STORE_PARENT"; echo "$STORE_PARENT"/*; "$test_directory/Bin/sed" --version > "$test_directory/output"'
+    # Test the 'userns' execution engine.
+    tarball="`guix pack -R -S /Bin=bin sed`"
+    (cd "$test_directory"; tar xvf "$tarball")
+
+    run_without_store "$test_directory/Bin/sed" --version > "$test_directory/output"
+    grep 'GNU sed' "$test_directory/output"
+
+    # Same with an explicit engine.
+    run_without_store GUIX_EXECUTION_ENGINE="userns" \
+                     "$test_directory/Bin/sed" --version > "$test_directory/output"
+    grep 'GNU sed' "$test_directory/output"
 
     # Check whether the exit code is preserved.
-    if unshare -mrf sh -c 'mount -t tmpfs none "$STORE_PARENT"; echo "$STORE_PARENT"/*; "$test_directory/Bin/sed" --does-not-exist';
-    then false; else true; fi
+    ! run_without_store "$test_directory/Bin/sed" --does-not-exist
+
+    chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
 else
-    # Run the relocatable 'sed' in the current namespaces.  This is a weak
-    # test because we're going to access store items from the host store.
-    "$test_directory/Bin/sed" --version > "$test_directory/output"
+    echo "'userns' execution tests skipped" >&2
 fi
-grep 'GNU sed' "$test_directory/output"
-chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
 
 case "`uname -m`" in
     x86_64|i?86)
        # Try '-RR' and PRoot.
        tarball="`guix pack -RR -S /Bin=bin sed`"
        tar tvf "$tarball" | grep /bin/proot
-       (cd "$test_directory"; tar xvf "$tarball")
-       GUIX_EXECUTION_ENGINE="proot"
-       export GUIX_EXECUTION_ENGINE
+       (cd "$test_directory"; tar xf "$tarball")
+       run_without_store GUIX_EXECUTION_ENGINE="proot" \
        "$test_directory/Bin/sed" --version > "$test_directory/output"
        grep 'GNU sed' "$test_directory/output"
 
        # Now with fakechroot.
-       GUIX_EXECUTION_ENGINE="fakechroot"
+       run_without_store GUIX_EXECUTION_ENGINE="fakechroot" \
        "$test_directory/Bin/sed" --version > "$test_directory/output"
        grep 'GNU sed' "$test_directory/output"
+       unset GUIX_EXECUTION_ENGINE
 
        chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
+
+       if unshare -r true
+       then
+           # Check whether the store contains everything it should.  Check
+           # once when erasing $STORE_PARENT ("/gnu") and once when erasing
+           # $NIX_STORE_DIR ("/gnu/store").
+           tarball="`guix pack -RR -S /bin=bin bash-minimal`"
+           (cd "$test_directory"; tar xf "$tarball")
+
+           STORE_PARENT="`dirname $NIX_STORE_DIR`"
+           export STORE_PARENT
+
+           for engine in userns proot fakechroot
+           do
+               for i in $(guix gc -R $(guix build bash-minimal | grep -v -e '-doc$'))
+               do
+                   unshare -mrf sh -c "mount -t tmpfs none \"$NIX_STORE_DIR\"; GUIX_EXECUTION_ENGINE=$engine $test_directory/bin/sh -c 'echo $NIX_STORE_DIR/*'" | grep $(basename $i)
+                   unshare -mrf sh -c "mount -t tmpfs none \"$STORE_PARENT\";  GUIX_EXECUTION_ENGINE=$engine $test_directory/bin/sh -c 'echo $NIX_STORE_DIR/*'" | grep $(basename $i)
+               done
+           done
+
+           chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
+       fi
        ;;
     *)
-       echo "skipping PRoot test" >&2
+       echo "skipping PRoot and Fakechroot tests" >&2
        ;;
 esac
 
+if unshare -r true
+then
+    # Check what happens if the wrapped binary forks and leaves child
+    # processes behind, like a daemon.  The root file system should remain
+    # available to those child processes.  See <https://bugs.gnu.org/44261>.
+    cat > "$test_directory/manifest.scm" <<EOF
+(use-modules (guix))
+
+(define daemon
+  (program-file "daemon"
+                #~(begin
+                    (use-modules (ice-9 match)
+                                 (ice-9 ftw))
+
+                    (call-with-output-file "parent-store"
+                      (lambda (port)
+                        (write (scandir (ungexp (%store-prefix)))
+                               port)))
+
+                    (match (primitive-fork)
+                      (0 (sigaction SIGHUP (const #t))
+                         (call-with-output-file "pid"
+                           (lambda (port)
+                             (display (getpid) port)))
+                         (pause)
+                         (call-with-output-file "child-store"
+                           (lambda (port)
+                             (write (scandir (ungexp (%store-prefix)))
+                                    port))))
+                      (_ #t)))))
+
+(define package
+  (computed-file "package"
+                 #~(let ((out (ungexp output)))
+                     (mkdir out)
+                     (mkdir (string-append out "/bin"))
+                     (symlink (ungexp daemon)
+                              (string-append out "/bin/daemon")))))
+
+(manifest (list (manifest-entry
+                  (name "daemon")
+                  (version "0")
+                  (item package))))
+EOF
+
+    tarball="$(guix pack -S /bin=bin -R -m "$test_directory/manifest.scm")"
+    (cd "$test_directory"; tar xf "$tarball")
+
+    # Run '/bin/daemon', which forks, then wait for the child, send it SIGHUP
+    # so that it dumps its view of the store, and make sure the child and
+    # parent both see the same store contents.
+    (cd "$test_directory"; run_without_store ./bin/daemon)
+    wait_for_file "$test_directory/pid"
+    kill -HUP $(cat "$test_directory/pid")
+    wait_for_file "$test_directory/child-store"
+    diff -u "$test_directory/parent-store" "$test_directory/child-store"
+
+    chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
+fi
+
 # Ensure '-R' works with outputs other than "out".
 tarball="`guix pack -R -S /share=share groff:doc`"
-(cd "$test_directory"; tar xvf "$tarball")
+(cd "$test_directory"; tar xf "$tarball")
 test -d "$test_directory/share/doc/groff/html"
+chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
+
+# Ensure '-R' applies to propagated inputs.  Failing to do that, it would fail
+# with a profile collision error in this case because 'python-scipy'
+# propagates 'python-numpy'.  See <https://bugs.gnu.org/42510>.
+guix pack -RR python-numpy python-scipy --no-grafts -n
+
+# Check that packages that mix executable and support files (e.g. git) in the
+# "binary" directories still work after wrapped.
+cat >"$test_directory/manifest.scm" <<'EOF'
+(use-modules (guix) (guix profiles) (guix search-paths)
+             (gnu packages bootstrap))
+(manifest
+ (list (manifest-entry
+        (name "test") (version "0")
+        (item (file-union "test"
+                          `(("bin/hello"
+                             ,(program-file
+                               "hello"
+                               #~(begin
+                                   (add-to-load-path (getenv "HELLO_EXEC_PATH"))
+                                   (display (load-from-path "msg"))(newline))
+                               #:guile %bootstrap-guile))
+                            ("libexec/hello/msg"
+                             ,(plain-file "msg" "42")))))
+        (search-paths
+         (list (search-path-specification
+                (variable "HELLO_EXEC_PATH")
+                (files '("libexec/hello"))
+                (separator #f)))))))
+EOF
+tarball="`guix pack -RR -S /opt= -m $test_directory/manifest.scm`"
+(cd "$test_directory"; tar xvf "$tarball")
+( export GUIX_PROFILE=$test_directory/opt
+  . $GUIX_PROFILE/etc/profile
+  run_without_store "$test_directory/opt/bin/hello" > "$test_directory/output" )
+cat "$test_directory/output"
+test "`cat $test_directory/output`" = "42"