summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/derivations.scm14
-rw-r--r--tests/gexp.scm49
-rw-r--r--tests/gremlin.scm69
-rw-r--r--tests/guix-archive.sh3
-rw-r--r--tests/guix-build.sh82
-rw-r--r--tests/guix-daemon.sh4
-rw-r--r--tests/guix-package-net.sh178
-rw-r--r--tests/guix-package.sh176
-rw-r--r--tests/guix-system.sh2
-rw-r--r--tests/hackage.scm134
-rw-r--r--tests/lint.scm30
-rw-r--r--tests/packages.scm93
-rw-r--r--tests/profiles.scm113
-rw-r--r--tests/publish.scm114
-rw-r--r--tests/store.scm22
-rw-r--r--tests/substitute.scm (renamed from tests/substitute-binary.scm)58
-rw-r--r--tests/syscalls.scm6
-rw-r--r--tests/utils.scm3
18 files changed, 953 insertions, 197 deletions
diff --git a/tests/derivations.scm b/tests/derivations.scm
index 72d253c465..a8cccac34a 100644
--- a/tests/derivations.scm
+++ b/tests/derivations.scm
@@ -499,6 +499,20 @@
            (string=? path (derivation-file-name (%guile-for-build)))))
          (derivation-prerequisites drv))))
 
+(test-assert "derivation-prerequisites and derivation-input-is-valid?"
+  (let* ((a (build-expression->derivation %store "a" '(mkdir %output)))
+         (b (build-expression->derivation %store "b" `(list ,(random-text))))
+         (c (build-expression->derivation %store "c" `(mkdir %output)
+                                          #:inputs `(("a" ,a) ("b" ,b)))))
+    (build-derivations %store (list a))
+    (match (derivation-prerequisites c
+                                     (cut valid-derivation-input? %store
+                                          <>))
+      ((($ <derivation-input> file ("out")))
+       (string=? file (derivation-file-name b)))
+      (x
+       (pk 'fail x #f)))))
+
 (test-assert "build-expression->derivation without inputs"
   (let* ((builder    '(begin
                         (mkdir %output)
diff --git a/tests/gexp.scm b/tests/gexp.scm
index 4c31e22f15..f81ef39860 100644
--- a/tests/gexp.scm
+++ b/tests/gexp.scm
@@ -97,6 +97,18 @@
                               %store (package-source coreutils))))
                  (gexp->sexp* exp)))))
 
+(test-assert "one local file"
+  (let* ((file  (search-path %load-path "guix.scm"))
+         (local (local-file file))
+         (exp   (gexp (display (ungexp local))))
+         (intd  (add-to-store %store (basename file) #t
+                              "sha256" file)))
+    (and (gexp? exp)
+         (match (gexp-inputs exp)
+           (((x "out"))
+            (eq? x local)))
+         (equal? `(display ,intd) (gexp->sexp* exp)))))
+
 (test-assert "same input twice"
   (let ((exp (gexp (begin
                      (display (ungexp coreutils))
@@ -160,6 +172,12 @@
          (equal? `(list ,guile ,cu ,libc ,bu)
                  (gexp->sexp* exp target)))))
 
+(test-equal "ungexp + ungexp-native, nested"
+  (list `((,%bootstrap-guile "out")) '<> `((,coreutils "out")))
+  (let* ((exp (gexp (list (ungexp-native (gexp (ungexp coreutils)))
+                          (ungexp %bootstrap-guile)))))
+    (list (gexp-inputs exp) '<> (gexp-native-inputs exp))))
+
 (test-assert "input list"
   (let ((exp   (gexp (display
                       '(ungexp (list %bootstrap-guile coreutils)))))
@@ -330,6 +348,20 @@
     (mlet %store-monad ((drv mdrv))
       (return (string=? system (derivation-system drv))))))
 
+(test-assertm "gexp->derivation, local-file"
+  (mlet* %store-monad ((file ->  (search-path %load-path "guix.scm"))
+                       (intd     (interned-file file))
+                       (local -> (local-file file))
+                       (exp ->   (gexp (begin
+                                         (stat (ungexp local))
+                                         (symlink (ungexp local)
+                                                  (ungexp output)))))
+                       (drv      (gexp->derivation "local-file" exp)))
+    (mbegin %store-monad
+      (built-derivations (list drv))
+      (return (string=? (readlink (derivation->output-path drv))
+                        intd)))))
+
 (test-assertm "gexp->derivation, cross-compilation"
   (mlet* %store-monad ((target -> "mips64el-linux")
                        (exp    -> (gexp (list (ungexp coreutils)
@@ -497,6 +529,23 @@
                                              (list "out" %bootstrap-guile))))
     (built-derivations (list drv))))
 
+(test-assertm "gexp->derivation #:allowed-references, specific output"
+  (mlet* %store-monad ((in  (gexp->derivation "thing"
+                                              #~(begin
+                                                  (mkdir #$output:ok)
+                                                  (mkdir #$output:not-ok))))
+                       (drv (gexp->derivation "allowed-refs"
+                                              #~(begin
+                                                  (pk #$in:not-ok)
+                                                  (mkdir #$output)
+                                                  (chdir #$output)
+                                                  (symlink #$output "self")
+                                                  (symlink #$in:ok "ok"))
+                                              #:allowed-references
+                                              (list "out"
+                                                    (gexp-input in "ok")))))
+    (built-derivations (list drv))))
+
 (test-assert "gexp->derivation #:allowed-references, disallowed"
   (let ((drv (run-with-store %store
                (gexp->derivation "allowed-refs"
diff --git a/tests/gremlin.scm b/tests/gremlin.scm
new file mode 100644
index 0000000000..dc9f78c21a
--- /dev/null
+++ b/tests/gremlin.scm
@@ -0,0 +1,69 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 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 (test-gremlin)
+  #:use-module (guix elf)
+  #:use-module (guix build utils)
+  #:use-module (guix build gremlin)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
+  #:use-module (srfi srfi-64)
+  #:use-module (rnrs io ports)
+  #:use-module (ice-9 match))
+
+(define %guile-executable
+  (match (command-line)
+    ((program . _)
+     (and (file-exists? program) (elf-file? program)
+          program))
+    (_
+     #f)))
+
+(define read-elf
+  (compose parse-elf get-bytevector-all))
+
+
+(test-begin "gremlin")
+
+(unless %guile-executable (test-skip 1))
+(test-assert "elf-dynamic-info-needed, executable"
+  (let* ((elf     (call-with-input-file %guile-executable read-elf))
+         (dyninfo (elf-dynamic-info elf)))
+    (or (not dyninfo)                             ;static executable
+        (lset<= string=?
+                (list (string-append "libguile-" (effective-version))
+                      "libgc" "libunistring" "libffi")
+                (map (lambda (lib)
+                       (string-take lib (string-contains lib ".so")))
+                     (elf-dynamic-info-needed dyninfo))))))
+
+(test-equal "expand-origin"
+  '("OOO/../lib"
+    "OOO"
+    "../OOO/bar/OOO/baz"
+    "ORIGIN/foo")
+  (map (cut expand-origin <> "OOO")
+       '("$ORIGIN/../lib"
+         "${ORIGIN}"
+         "../${ORIGIN}/bar/$ORIGIN/baz"
+         "ORIGIN/foo")))
+
+(test-end "gremlin")
+
+
+(exit (= (test-runner-fail-count (test-runner-current)) 0))
diff --git a/tests/guix-archive.sh b/tests/guix-archive.sh
index d4259b8677..8eacf89338 100644
--- a/tests/guix-archive.sh
+++ b/tests/guix-archive.sh
@@ -1,5 +1,5 @@
 # GNU Guix --- Functional package management for GNU
-# Copyright © 2013, 2014 Ludovic Courtès <ludo@gnu.org>
+# Copyright © 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
 #
 # This file is part of GNU Guix.
 #
@@ -41,7 +41,6 @@ cmp "$archive" "$archive_alt"
 
 # Check the exit value and stderr upon import.
 guix archive --import < "$archive"
-guix archive --import < "$archive" 2>&1 | grep "import.*guile-bootstrap"
 
 if guix archive something-that-does-not-exist
 then false; else true; fi
diff --git a/tests/guix-build.sh b/tests/guix-build.sh
index 836c45e776..a72ce0911d 100644
--- a/tests/guix-build.sh
+++ b/tests/guix-build.sh
@@ -36,6 +36,88 @@ guix build -e '(@@ (gnu packages bootstrap) %bootstrap-guile)' |	\
 guix build hello -d |				\
     grep -e '-hello-[0-9\.]\+\.drv$'
 
+# Check --sources option with its arguments
+module_dir="t-guix-build-$$"
+mkdir "$module_dir"
+trap "rm -rf $module_dir" EXIT
+
+cat > "$module_dir/foo.scm"<<EOF
+(define-module (foo)
+  #:use-module (guix packages)
+  #:use-module (guix download)
+  #:use-module (guix build-system trivial))
+
+(define-public foo
+  (package
+    (name "foo")
+    (version "42")
+    (source (origin
+              (method url-fetch)
+              (uri "http://www.example.com/foo.tar.gz")
+              (sha256
+               (base32
+                "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"))))
+    (build-system trivial-build-system)
+    (inputs
+     (quasiquote (("bar" ,bar))))
+    (home-page "www.example.com")
+    (synopsis "Dummy package")
+    (description "foo is a dummy package for testing.")
+    (license #f)))
+
+(define-public bar
+  (package
+    (name "bar")
+    (version "9001")
+    (source (origin
+              (method url-fetch)
+              (uri "http://www.example.com/bar.tar.gz")
+              (sha256
+               (base32
+                "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"))))
+    (build-system trivial-build-system)
+    (inputs
+     (quasiquote
+      (("data" ,(origin
+                 (method url-fetch)
+                 (uri "http://www.example.com/bar.dat")
+                 (sha256
+                  (base32
+                   "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz")))))))
+    (home-page "www.example.com")
+    (synopsis "Dummy package")
+    (description "bar is a dummy package for testing.")
+    (license #f)))
+EOF
+
+GUIX_PACKAGE_PATH="$module_dir"
+export GUIX_PACKAGE_PATH
+
+# foo.tar.gz
+guix build -d -S foo
+guix build -d -S foo | grep -e 'foo\.tar\.gz'
+
+guix build -d --sources=package foo
+guix build -d --sources=package foo | grep -e 'foo\.tar\.gz'
+
+# bar.tar.gz and bar.dat
+guix build -d --sources bar
+test `guix build -d --sources bar \
+      | grep -e 'bar\.tar\.gz' -e 'bar\.dat' \
+      | wc -l` -eq 2
+
+# bar.tar.gz and bar.dat
+guix build -d --sources=all bar
+test `guix build -d --sources bar \
+      | grep -e 'bar\.tar\.gz' -e 'bar\.dat' \
+      | wc -l` -eq 2
+
+# Should include foo.tar.gz, bar.tar.gz, and bar.dat
+guix build -d --sources=transitive foo
+test `guix build -d --sources=transitive foo \
+      | grep -e 'foo\.tar\.gz' -e 'bar\.tar\.gz' -e 'bar\.dat' \
+      | wc -l` -eq 3
+
 # Should all return valid log files.
 drv="`guix build -d -e '(@@ (gnu packages bootstrap) %bootstrap-guile)'`"
 out="`guix build -e '(@@ (gnu packages bootstrap) %bootstrap-guile)'`"
diff --git a/tests/guix-daemon.sh b/tests/guix-daemon.sh
index a73c9e22e3..87f17def12 100644
--- a/tests/guix-daemon.sh
+++ b/tests/guix-daemon.sh
@@ -17,7 +17,7 @@
 # along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
 
 #
-# Test the daemon and its interaction with 'guix substitute-binary'.
+# Test the daemon and its interaction with 'guix substitute'.
 #
 
 set -e
@@ -51,7 +51,7 @@ Deriver: $drv
 EOF
 
 # Remove the cached narinfo.
-rm -f "$XDG_CACHE_HOME/guix/substitute-binary/$hash_part"
+rm -f "$XDG_CACHE_HOME/guix/substitute/$hash_part"
 
 # Make sure we see the substitute.
 guile -c '
diff --git a/tests/guix-package-net.sh b/tests/guix-package-net.sh
new file mode 100644
index 0000000000..14222cfd25
--- /dev/null
+++ b/tests/guix-package-net.sh
@@ -0,0 +1,178 @@
+# GNU Guix --- Functional package management for GNU
+# Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+# Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.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/>.
+
+#
+# Test the `guix package' command-line utility.  This test requires network
+# access and is skipped when that is lacking.
+#
+
+guix package --version
+
+readlink_base ()
+{
+    basename `readlink "$1"`
+}
+
+# Return true if a typical shebang in the store would exceed Linux's default
+# static limit.
+shebang_too_long ()
+{
+    test `echo $NIX_STORE_DIR/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bootstrap-binaries-0/bin/bash | wc -c` \
+	 -ge 128
+}
+
+if ! guile -c '(getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV)' 2> /dev/null \
+	|| shebang_too_long
+then
+    # Skipping.
+    exit 77
+fi
+
+
+profile="t-profile-$$"
+rm -f "$profile"
+
+trap 'rm -f "$profile" "$profile-"[0-9]* ; rm -rf t-home-'"$$" EXIT
+
+
+guix package --bootstrap -p "$profile" -i guile-bootstrap
+test -L "$profile" && test -L "$profile-1-link"
+! test -f "$profile-2-link"
+test -f "$profile/bin/guile"
+
+boot_make="(@@ (gnu packages commencement) gnu-make-boot0)"
+boot_make_drv="`guix build -e "$boot_make" | grep -v -e -debug`"
+guix package --bootstrap -p "$profile" -i "$boot_make_drv"
+test -L "$profile-2-link"
+test -f "$profile/bin/make" && test -f "$profile/bin/guile"
+
+# Check whether `--list-installed' works.
+# XXX: Change the tests when `--install' properly extracts the package
+# name and version string.
+installed="`guix package -p "$profile" --list-installed | cut -f1 | xargs echo | sort`"
+case "x$installed" in
+    "guile-bootstrap make-boot0")
+        true;;
+    "make-boot0 guile-bootstrap")
+        true;;
+    "*")
+        false;;
+esac
+
+test "`guix package -p "$profile" -I 'g.*e' | cut -f1`" = "guile-bootstrap"
+
+# List generations.
+test "`guix package -p "$profile" -l | cut -f1 | grep guile | head -n1`" \
+     = "  guile-bootstrap"
+
+# Exit with 1 when a generation does not exist.
+if guix package -p "$profile" --list-generations=42;
+then false; else true; fi
+if guix package -p "$profile" --switch-generation=99;
+then false; else true; fi
+
+# Remove a package.
+guix package --bootstrap -p "$profile" -r "guile-bootstrap"
+test -L "$profile-3-link"
+test -f "$profile/bin/make" && ! test -f "$profile/bin/guile"
+
+# Roll back.
+guix package --roll-back -p "$profile"
+test "`readlink_base "$profile"`" = "$profile-2-link"
+test -x "$profile/bin/guile" && test -x "$profile/bin/make"
+guix package --roll-back -p "$profile"
+test "`readlink_base "$profile"`" = "$profile-1-link"
+test -x "$profile/bin/guile" && ! test -x "$profile/bin/make"
+
+# Switch to the rolled generation and switch back.
+guix package -p "$profile" --switch-generation=2
+test "`readlink_base "$profile"`" = "$profile-2-link"
+guix package -p "$profile" --switch-generation=-1
+test "`readlink_base "$profile"`" = "$profile-1-link"
+
+# Move to the empty profile.
+for i in `seq 1 3`
+do
+    guix package --bootstrap --roll-back -p "$profile"
+    ! test -f "$profile/bin"
+    ! test -f "$profile/lib"
+    test "`readlink_base "$profile"`" = "$profile-0-link"
+done
+
+# Test that '--list-generations' does not output the zeroth generation.
+test -z "`guix package -p "$profile" -l 0`"
+
+# Reinstall after roll-back to the empty profile.
+guix package --bootstrap -p "$profile" -e "$boot_make"
+test "`readlink_base "$profile"`" = "$profile-1-link"
+test -x "$profile/bin/guile" && ! test -x "$profile/bin/make"
+
+# Check that the first generation is the current one.
+test "`guix package -p "$profile" -l 1 | cut -f3 | head -n1`" = "(current)"
+
+# Roll-back to generation 0, and install---all at once.
+guix package --bootstrap -p "$profile" --roll-back -i guile-bootstrap
+test "`readlink_base "$profile"`" = "$profile-1-link"
+test -x "$profile/bin/guile" && ! test -x "$profile/bin/make"
+
+# Install Make.
+guix package --bootstrap -p "$profile" -e "$boot_make"
+test "`readlink_base "$profile"`" = "$profile-2-link"
+test -x "$profile/bin/guile" && test -x "$profile/bin/make"
+grep "`guix build -e "$boot_make"`" "$profile/manifest"
+
+# Make a "hole" in the list of generations, and make sure we can
+# roll back and switch "over" it.
+rm "$profile-1-link"
+guix package --bootstrap -p "$profile" --roll-back
+test "`readlink_base "$profile"`" = "$profile-0-link"
+guix package -p "$profile" --switch-generation=+1
+test "`readlink_base "$profile"`" = "$profile-2-link"
+
+# Make sure LIBRARY_PATH gets listed by `--search-paths'.
+guix package --bootstrap -p "$profile" -i guile-bootstrap -i gcc-bootstrap
+guix package -p "$profile" --search-paths | grep LIBRARY_PATH
+
+# Roll back so we can delete #3 below.
+guix package -p "$profile" --switch-generation=2
+
+# Delete the third generation and check that it was actually deleted.
+guix package -p "$profile" --delete-generations=3
+test -z "`guix package -p "$profile" -l 3`"
+
+
+#
+# Try with the default profile.
+#
+
+XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
+export XDG_CACHE_HOME
+HOME="$PWD/t-home-$$"
+export HOME
+
+mkdir -p "$HOME"
+
+# Get the canonical directory name so that 'guix package' recognizes it.
+HOME="`cd $HOME; pwd -P`"
+
+guix package --bootstrap -e "$boot_make"
+test -f "$HOME/.guix-profile/bin/make"
+
+guix package --bootstrap --roll-back
+! test -f "$HOME/.guix-profile/bin/make"
diff --git a/tests/guix-package.sh b/tests/guix-package.sh
index 94cf927420..26a5e9d1a2 100644
--- a/tests/guix-package.sh
+++ b/tests/guix-package.sh
@@ -28,14 +28,6 @@ readlink_base ()
     basename `readlink "$1"`
 }
 
-# Return true if a typical shebang in the store would not exceed Linux's
-# default static limit.
-shebang_not_too_long ()
-{
-    test `echo $NIX_STORE_DIR/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bootstrap-binaries-0/bin/bash | wc -c` \
-	 -lt 128
-}
-
 module_dir="t-guix-package-$$"
 profile="t-profile-$$"
 rm -f "$profile"
@@ -60,118 +52,20 @@ test -L "$profile" && test -L "$profile-1-link"
 test -f "$profile/bin/guile"
 
 # No search path env. var. here.
-guix package --search-paths -p "$profile"
-test "`guix package --search-paths -p "$profile" | wc -l`" = 0
-
-# Check whether we have network access and an acceptable shebang length.
-if guile -c '(getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV)' 2> /dev/null \
-	 && shebang_not_too_long
-then
-    boot_make="(@@ (gnu packages commencement) gnu-make-boot0)"
-    boot_make_drv="`guix build -e "$boot_make" | grep -v -e -debug`"
-    guix package --bootstrap -p "$profile" -i "$boot_make_drv"
-    test -L "$profile-2-link"
-    test -f "$profile/bin/make" && test -f "$profile/bin/guile"
-
-
-    # Check whether `--list-installed' works.
-    # XXX: Change the tests when `--install' properly extracts the package
-    # name and version string.
-    installed="`guix package -p "$profile" --list-installed | cut -f1 | xargs echo | sort`"
-    case "x$installed" in
-        "guile-bootstrap make-boot0")
-            true;;
-        "make-boot0 guile-bootstrap")
-            true;;
-        "*")
-            false;;
-    esac
-
-    test "`guix package -p "$profile" -I 'g.*e' | cut -f1`" = "guile-bootstrap"
-
-    # List generations.
-    test "`guix package -p "$profile" -l | cut -f1 | grep guile | head -n1`" \
-        = "  guile-bootstrap"
-
-    # Exit with 1 when a generation does not exist.
-    if guix package -p "$profile" --list-generations=42;
-    then false; else true; fi
-    if guix package -p "$profile" --switch-generation=99;
-    then false; else true; fi
-
-    # Remove a package.
-    guix package --bootstrap -p "$profile" -r "guile-bootstrap"
-    test -L "$profile-3-link"
-    test -f "$profile/bin/make" && ! test -f "$profile/bin/guile"
-
-    # Roll back.
-    guix package --roll-back -p "$profile"
-    test "`readlink_base "$profile"`" = "$profile-2-link"
-    test -x "$profile/bin/guile" && test -x "$profile/bin/make"
-    guix package --roll-back -p "$profile"
-    test "`readlink_base "$profile"`" = "$profile-1-link"
-    test -x "$profile/bin/guile" && ! test -x "$profile/bin/make"
-
-    # Switch to the rolled generation and switch back.
-    guix package -p "$profile" --switch-generation=2
-    test "`readlink_base "$profile"`" = "$profile-2-link"
-    guix package -p "$profile" --switch-generation=-1
-    test "`readlink_base "$profile"`" = "$profile-1-link"
-
-    # Move to the empty profile.
-    for i in `seq 1 3`
-    do
-        guix package --bootstrap --roll-back -p "$profile"
-        ! test -f "$profile/bin"
-        ! test -f "$profile/lib"
-        test "`readlink_base "$profile"`" = "$profile-0-link"
-    done
-
-    # Test that '--list-generations' does not output the zeroth generation.
-    test -z "`guix package -p "$profile" -l 0`"
-
-    # Reinstall after roll-back to the empty profile.
-    guix package --bootstrap -p "$profile" -e "$boot_make"
-    test "`readlink_base "$profile"`" = "$profile-1-link"
-    test -x "$profile/bin/guile" && ! test -x "$profile/bin/make"
-
-    # Check that the first generation is the current one.
-    test "`guix package -p "$profile" -l 1 | cut -f3 | head -n1`" = "(current)"
-
-    # Roll-back to generation 0, and install---all at once.
-    guix package --bootstrap -p "$profile" --roll-back -i guile-bootstrap
-    test "`readlink_base "$profile"`" = "$profile-1-link"
-    test -x "$profile/bin/guile" && ! test -x "$profile/bin/make"
-
-    # Install Make.
-    guix package --bootstrap -p "$profile" -e "$boot_make"
-    test "`readlink_base "$profile"`" = "$profile-2-link"
-    test -x "$profile/bin/guile" && test -x "$profile/bin/make"
-    grep "`guix build -e "$boot_make"`" "$profile/manifest"
-
-    # Make a "hole" in the list of generations, and make sure we can
-    # roll back and switch "over" it.
-    rm "$profile-1-link"
-    guix package --bootstrap -p "$profile" --roll-back
-    test "`readlink_base "$profile"`" = "$profile-0-link"
-    guix package -p "$profile" --switch-generation=+1
-    test "`readlink_base "$profile"`" = "$profile-2-link"
-
-    # Make sure LIBRARY_PATH gets listed by `--search-paths'.
-    guix package --bootstrap -p "$profile" -i guile-bootstrap -i gcc-bootstrap
-    guix package --search-paths -p "$profile" | grep LIBRARY_PATH
-
-    # Delete the third generation and check that it was actually deleted.
-    guix package -p "$profile" --delete-generations=3
-    test -z "`guix package -p "$profile" -l 3`"
-
-    # Exit with 1 when a generation does not exist.
-    if guix package -p "$profile" --delete-generations=42;
-    then false; else true; fi
-
-    # Exit with 0 when trying to delete the zeroth generation.
-    guix package -p "$profile" --delete-generations=0
-fi
+guix package -p "$profile" --search-paths
+guix package -p "$profile" --search-paths | grep '^export PATH='
+test "`guix package -p "$profile" --search-paths | wc -l`" = 1  # $PATH
+( set -e; set -x;						\
+  eval `guix package --search-paths=prefix -p "$PWD/$profile"`;	\
+  test "`type -P guile`" = "$PWD/$profile/bin/guile" ;		\
+  type -P rm )
+
+# Exit with 1 when a generation does not exist.
+if guix package -p "$profile" --delete-generations=42;
+then false; else true; fi
+
+# Exit with 0 when trying to delete the zeroth generation.
+guix package -p "$profile" --delete-generations=0
 
 # Make sure multiple arguments to -i works.
 guix package --bootstrap -i guile gcc -p "$profile" -n
@@ -212,6 +106,14 @@ if guix package -p "$profile" --delete-generations=12m;
 then false; else true; fi
 test "`readlink_base "$profile"`" = "$generation"
 
+# The following command should not delete the current generation, even though
+# it matches the given pattern (see <http://bugs.gnu.org/19978>.)  And since
+# there's nothing else to delete, it should just fail.
+guix package --list-generations -p "$profile"
+if guix package --bootstrap -p "$profile" --delete-generations=1..
+then false; else true; fi
+test "`readlink_base "$profile"`" = "$generation"
+
 # Make sure $profile is a GC root at this point.
 real_profile="`readlink -f "$profile"`"
 if guix gc -d "$real_profile"
@@ -242,18 +144,6 @@ guix package --bootstrap -i guile-bootstrap
 test -L "$HOME/.guix-profile"
 test -f "$HOME/.guix-profile/bin/guile"
 
-if guile -c '(getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV)' 2> /dev/null
-then
-    guix package --bootstrap -e "$boot_make"
-    test -f "$HOME/.guix-profile/bin/make"
-    first_environment="`cd $HOME/.guix-profile ; pwd`"
-
-    guix package --bootstrap --roll-back
-    test -f "$HOME/.guix-profile/bin/guile"
-    ! test -f "$HOME/.guix-profile/bin/make"
-    test "`cd $HOME/.guix-profile ; pwd`" = "$first_environment"
-fi
-
 # Move to the empty profile.
 default_profile="`readlink "$HOME/.guix-profile"`"
 for i in `seq 1 3`
@@ -327,9 +217,19 @@ cat > "$module_dir/foo.scm"<<EOF
               (patches (list (search-patch "emacs.patch")))))
     (name "emacs-foo-bar-patched")
     (version "42")))
+
+(define-public y
+  (package (inherit emacs)
+    (name "super-non-portable-emacs")
+    (supported-systems '("foobar64-hurd"))))
 EOF
 guix package -i emacs-foo-bar-patched -n
 
+# This one should not show up in searches since it's no supported on the
+# current system.
+test "`guix package -A super-non-portable-emacs`" = ""
+test "`guix package -s super-non-portable-emacs | grep ^systems:`" = "systems: "
+
 unset GUIX_PACKAGE_PATH
 
 # Using 'GUIX_BUILD_OPTIONS'.
@@ -342,3 +242,15 @@ export GUIX_BUILD_OPTIONS
 available2="`guix package -A | sort`"
 test "$available2" = "$available"
 guix package -I
+
+unset GUIX_BUILD_OPTIONS
+
+# Applying a manifest file
+cat > "$module_dir/manifest.scm"<<EOF
+(use-package-modules bootstrap)
+
+(packages->manifest (list %bootstrap-guile))
+EOF
+guix package --bootstrap -m "$module_dir/manifest.scm"
+guix package -I | grep guile
+test `guix package -I | wc -l` -eq 1
diff --git a/tests/guix-system.sh b/tests/guix-system.sh
index 76e722fbc1..1b77d1a0db 100644
--- a/tests/guix-system.sh
+++ b/tests/guix-system.sh
@@ -17,7 +17,7 @@
 # along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
 
 #
-# Test the daemon and its interaction with 'guix substitute-binary'.
+# Test the daemon and its interaction with 'guix substitute'.
 #
 
 set -e
diff --git a/tests/hackage.scm b/tests/hackage.scm
new file mode 100644
index 0000000000..23b854caa4
--- /dev/null
+++ b/tests/hackage.scm
@@ -0,0 +1,134 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch>
+;;;
+;;; 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 (test-hackage)
+  #:use-module (guix import hackage)
+  #:use-module (guix tests)
+  #:use-module (srfi srfi-64)
+  #:use-module (ice-9 match))
+
+(define test-cabal-1
+  "name: foo
+version: 1.0.0
+homepage: http://test.org
+synopsis: synopsis
+description: description
+license: BSD3
+executable cabal
+  build-depends:
+    HTTP       >= 4000.2.5 && < 4000.3,
+    mtl        >= 2.0      && < 3
+")
+
+;; Use TABs to indent lines and to separate keys from value.
+(define test-cabal-2
+  "name:	foo
+version:	1.0.0
+homepage:	http://test.org
+synopsis:	synopsis
+description:	description
+license:	BSD3
+executable cabal
+	build-depends:	HTTP       >= 4000.2.5 && < 4000.3,
+		mtl        >= 2.0      && < 3
+")
+
+;; Use indentation with comma as found, e.g., in 'haddock-api'.
+(define test-cabal-3
+  "name: foo
+version: 1.0.0
+homepage: http://test.org
+synopsis: synopsis
+description: description
+license: BSD3
+executable cabal
+    build-depends:
+        HTTP       >= 4000.2.5 && < 4000.3
+      , mtl        >= 2.0      && < 3
+")
+
+(define test-cond-1
+  "(os(darwin) || !(flag(debug))) && flag(cips)")
+
+(define read-cabal
+  (@@ (guix import hackage) read-cabal))
+
+(define eval-cabal-keywords
+  (@@ (guix import hackage) eval-cabal-keywords))
+
+(define conditional->sexp-like
+  (@@ (guix import hackage) conditional->sexp-like))
+
+(test-begin "hackage")
+
+(define (eval-test-with-cabal test-cabal)
+  (mock
+   ((guix import hackage) hackage-fetch
+    (lambda (name-version)
+      (call-with-input-string test-cabal
+        read-cabal)))
+   (match (hackage->guix-package "foo")
+     (('package
+        ('name "ghc-foo")
+        ('version "1.0.0")
+        ('source
+         ('origin
+           ('method 'url-fetch)
+           ('uri ('string-append
+                  "http://hackage.haskell.org/package/foo/foo-"
+                  'version
+                  ".tar.gz"))
+           ('sha256
+            ('base32
+             (? string? hash)))))
+        ('build-system 'haskell-build-system)
+        ('inputs
+         ('quasiquote
+          (("ghc-http" ('unquote 'ghc-http))
+           ("ghc-mtl" ('unquote 'ghc-mtl)))))
+        ('home-page "http://test.org")
+        ('synopsis (? string?))
+        ('description (? string?))
+        ('license 'bsd-3))
+      #t)
+     (x
+      (pk 'fail x #f)))))
+
+(test-assert "hackage->guix-package test 1"
+  (eval-test-with-cabal test-cabal-1))
+
+(test-assert "hackage->guix-package test 2"
+  (eval-test-with-cabal test-cabal-2))
+
+(test-assert "hackage->guix-package test 3"
+  (eval-test-with-cabal test-cabal-3))
+
+(test-assert "conditional->sexp-like"
+  (match
+    (eval-cabal-keywords
+     (conditional->sexp-like test-cond-1)
+     '(("debug" . "False")))
+    (('and ('or ('string-match "darwin" ('%current-system)) ('not '#f)) '#t)
+     #t)
+    (x
+     (pk 'fail x #f))))
+
+(test-end "hackage")
+
+
+(exit (= (test-runner-fail-count (test-runner-current)) 0))
diff --git a/tests/lint.scm b/tests/lint.scm
index c0599224b7..2807eba1cc 100644
--- a/tests/lint.scm
+++ b/tests/lint.scm
@@ -18,8 +18,7 @@
 ;;; 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 (test-packages)
+(define-module (test-lint)
   #:use-module (guix tests)
   #:use-module (guix download)
   #:use-module (guix build-system gnu)
@@ -302,9 +301,34 @@ requests."
                        (uri "someurl")
                        (sha256 "somesha")
                        (patches (list "/path/to/y.patch")))))))
-         (check-patches pkg)))
+         (check-patch-file-names pkg)))
      "file names of patches should start with the package name")))
 
+(test-assert "patches: not found"
+  (->bool
+   (string-contains
+     (with-warnings
+       (let ((pkg (dummy-package "x"
+                    (source
+                     (origin
+                       (method url-fetch)
+                       (uri "someurl")
+                       (sha256 "somesha")
+                       (patches
+                        (list (search-patch "this-patch-does-not-exist!"))))))))
+         (check-patch-file-names pkg)))
+     "patch not found")))
+
+(test-assert "derivation: invalid arguments"
+  (->bool
+   (string-contains
+    (with-warnings
+      (let ((pkg (dummy-package "x"
+                   (arguments
+                    '(#:imported-modules (invalid-module))))))
+        (check-derivation pkg)))
+    "failed to create derivation")))
+
 (test-assert "home-page: wrong home-page"
   (->bool
    (string-contains
diff --git a/tests/packages.scm b/tests/packages.scm
index c9dd5d859a..511ad78b6c 100644
--- a/tests/packages.scm
+++ b/tests/packages.scm
@@ -128,21 +128,82 @@
     ("y")                                         ;c
     ("y")                                         ;d
     ("y"))                                        ;e
-  (let* ((a (dummy-package "a" (supported-systems '("x" "y" "z"))))
-         (b (dummy-package "b" (supported-systems '("x" "y"))
-               (inputs `(("a" ,a)))))
-         (c (dummy-package "c" (supported-systems '("y" "z"))
-               (inputs `(("b" ,b)))))
-         (d (dummy-package "d" (supported-systems '("x" "y" "z"))
-               (inputs `(("b" ,b) ("c" ,c)))))
-         (e (dummy-package "e" (supported-systems '("x" "y" "z"))
-               (inputs `(("d" ,d))))))
+  ;; Use TRIVIAL-BUILD-SYSTEM because it doesn't add implicit inputs and thus
+  ;; doesn't restrict the set of supported systems.
+  (let* ((a (dummy-package "a"
+              (build-system trivial-build-system)
+              (supported-systems '("x" "y" "z"))))
+         (b (dummy-package "b"
+              (build-system trivial-build-system)
+              (supported-systems '("x" "y"))
+              (inputs `(("a" ,a)))))
+         (c (dummy-package "c"
+              (build-system trivial-build-system)
+              (supported-systems '("y" "z"))
+              (inputs `(("b" ,b)))))
+         (d (dummy-package "d"
+              (build-system trivial-build-system)
+              (supported-systems '("x" "y" "z"))
+              (inputs `(("b" ,b) ("c" ,c)))))
+         (e (dummy-package "e"
+              (build-system trivial-build-system)
+              (supported-systems '("x" "y" "z"))
+              (inputs `(("d" ,d))))))
     (list (package-transitive-supported-systems a)
           (package-transitive-supported-systems b)
           (package-transitive-supported-systems c)
           (package-transitive-supported-systems d)
           (package-transitive-supported-systems e))))
 
+(let* ((o (dummy-origin))
+       (u (dummy-origin))
+       (i (dummy-origin))
+       (a (dummy-package "a"))
+       (b (dummy-package "b"
+            (inputs `(("a" ,a) ("i" ,i)))))
+       (c (package (inherit b) (source o)))
+       (d (dummy-package "d"
+            (build-system trivial-build-system)
+            (source u) (inputs `(("c" ,c))))))
+  (test-assert "package-direct-sources, no source"
+    (null? (package-direct-sources a)))
+  (test-equal "package-direct-sources, #f source"
+    (list i)
+    (package-direct-sources b))
+  (test-equal "package-direct-sources, not input source"
+    (list u)
+    (package-direct-sources d))
+  (test-assert "package-direct-sources"
+    (let ((s (package-direct-sources c)))
+      (and (= (length (pk 's-sources s)) 2)
+           (member o s)
+           (member i s))))
+  (test-assert "package-transitive-sources"
+    (let ((s (package-transitive-sources d)))
+      (and (= (length (pk 'd-sources s)) 3)
+           (member o s)
+           (member i s)
+           (member u s)))))
+
+(test-equal "package-transitive-supported-systems, implicit inputs"
+  %supported-systems
+
+  ;; Here GNU-BUILD-SYSTEM adds implicit inputs that build only on
+  ;; %SUPPORTED-SYSTEMS.  Thus the others must be ignored.
+  (let ((p (dummy-package "foo"
+             (build-system gnu-build-system)
+             (supported-systems
+              `("does-not-exist" "foobar" ,@%supported-systems)))))
+    (package-transitive-supported-systems p)))
+
+(test-assert "supported-package?"
+  (let ((p (dummy-package "foo"
+             (build-system gnu-build-system)
+             (supported-systems '("x86_64-linux" "does-not-exist")))))
+    (and (supported-package? p "x86_64-linux")
+         (not (supported-package? p "does-not-exist"))
+         (not (supported-package? p "i686-linux")))))
+
 (test-skip (if (not %store) 8 0))
 
 (test-assert "package-source-derivation, file"
@@ -179,7 +240,11 @@
 (unless (network-reachable?) (test-skip 1))
 (test-equal "package-source-derivation, snippet"
   "OK"
-  (let* ((file   (search-bootstrap-binary "guile-2.0.9.tar.xz"
+  (let* ((file   (search-bootstrap-binary (match (%current-system)
+                                            ("armhf-linux"
+                                             "guile-2.0.11.tar.xz")
+                                            (_
+                                             "guile-2.0.9.tar.xz"))
                                           (%current-system)))
          (sha256 (call-with-input-file file port-sha256))
          (fetch  (lambda* (url hash-algo hash
@@ -205,10 +270,7 @@
                                 (chmod "." #o777)
                                 (symlink "guile" "guile-rocks")
                                 (copy-recursively "../share/guile/2.0/scripts"
-                                                  "scripts")
-
-                                ;; These variables must exist.
-                                (pk %build-inputs %outputs))))))
+                                                  "scripts"))))))
          (package (package (inherit (dummy-package "with-snippet"))
                     (source source)
                     (build-system trivial-build-system)
@@ -599,8 +661,7 @@
                  (profile-derivation
                   (manifest (map package->manifest-entry
                                  (list p1 p2)))
-                  #:info-dir? #f
-                  #:ca-certificate-bundle? #f)
+                  #:hooks '())
                  #:guile-for-build (%guile-for-build))))
     (build-derivations %store (list prof))
     (string-match (format #f "^export XML_CATALOG_FILES=\"~a/xml/+bar/baz/catalog\\.xml\"\n"
diff --git a/tests/profiles.scm b/tests/profiles.scm
index 7b942e35b0..cc9a822cee 100644
--- a/tests/profiles.scm
+++ b/tests/profiles.scm
@@ -24,10 +24,14 @@
   #:use-module (guix monads)
   #:use-module (guix packages)
   #:use-module (guix derivations)
+  #:use-module (guix build-system trivial)
   #:use-module (gnu packages bootstrap)
   #:use-module ((gnu packages base) #:prefix packages:)
+  #:use-module ((gnu packages guile) #:prefix packages:)
   #:use-module (ice-9 match)
   #:use-module (ice-9 regex)
+  #:use-module (ice-9 popen)
+  #:use-module (rnrs io ports)
   #:use-module (srfi srfi-11)
   #:use-module (srfi srfi-64))
 
@@ -183,8 +187,7 @@
       ((entry ->   (package->manifest-entry %bootstrap-guile))
        (guile      (package->derivation %bootstrap-guile))
        (drv        (profile-derivation (manifest (list entry))
-                                       #:info-dir? #f
-                                       #:ca-certificate-bundle? #f))
+                                       #:hooks '()))
        (profile -> (derivation->output-path drv))
        (bindir ->  (string-append profile "/bin"))
        (_          (built-derivations (list drv))))
@@ -196,10 +199,112 @@
   (mlet* %store-monad
       ((entry ->   (package->manifest-entry packages:glibc "debug"))
        (drv        (profile-derivation (manifest (list entry))
-                                       #:info-dir? #f
-                                       #:ca-certificate-bundle? #f)))
+                                       #:hooks '())))
     (return (derivation-inputs drv))))
 
+(test-assertm "profile-manifest, search-paths"
+  (mlet* %store-monad
+      ((guile ->   (package
+                     (inherit %bootstrap-guile)
+                     (native-search-paths
+                      (package-native-search-paths packages:guile-2.0))))
+       (entry ->   (package->manifest-entry guile))
+       (drv        (profile-derivation (manifest (list entry))
+                                       #:hooks '()))
+       (profile -> (derivation->output-path drv)))
+    (mbegin %store-monad
+      (built-derivations (list drv))
+
+      ;; Read the manifest back and make sure search paths are preserved.
+      (let ((manifest (profile-manifest profile)))
+        (match (manifest-entries manifest)
+          ((result)
+           (return (equal? (manifest-entry-search-paths result)
+                           (manifest-entry-search-paths entry)
+                           (package-native-search-paths
+                            packages:guile-2.0)))))))))
+
+(test-assertm "etc/profile"
+  ;; Make sure we get an 'etc/profile' file that at least defines $PATH.
+  (mlet* %store-monad
+      ((guile ->   (package
+                     (inherit %bootstrap-guile)
+                     (native-search-paths
+                      (package-native-search-paths packages:guile-2.0))))
+       (entry ->   (package->manifest-entry guile))
+       (drv        (profile-derivation (manifest (list entry))
+                                       #:hooks '()))
+       (profile -> (derivation->output-path drv)))
+    (mbegin %store-monad
+      (built-derivations (list drv))
+      (let* ((pipe (open-input-pipe
+                    (string-append "unset GUIX_PROFILE; "
+                                   ;; 'source' is a Bashism; use '.' (dot).
+                                   ". " profile "/etc/profile; "
+                                   ;; Don't try to parse set(1) output because
+                                   ;; it differs among shells; just use echo.
+                                   "echo $PATH")))
+             (path (get-string-all pipe)))
+        (return
+         (and (zero? (close-pipe pipe))
+              (string-contains path (string-append profile "/bin"))))))))
+
+(test-assertm "etc/profile when etc/ already exists"
+  ;; Here 'union-build' makes the profile's etc/ a symlink to the package's
+  ;; etc/ directory, which makes it read-only.  Make sure the profile build
+  ;; handles that.
+  (mlet* %store-monad
+      ((thing ->   (dummy-package "dummy"
+                     (build-system trivial-build-system)
+                     (arguments
+                      `(#:guile ,%bootstrap-guile
+                        #:builder
+                        (let ((out (assoc-ref %outputs "out")))
+                          (mkdir out)
+                          (mkdir (string-append out "/etc"))
+                          (call-with-output-file (string-append out "/etc/foo")
+                            (lambda (port)
+                              (display "foo!" port))))))))
+       (entry ->   (package->manifest-entry thing))
+       (drv        (profile-derivation (manifest (list entry))
+                                       #:hooks '()))
+       (profile -> (derivation->output-path drv)))
+    (mbegin %store-monad
+      (built-derivations (list drv))
+      (return (and (file-exists? (string-append profile "/etc/profile"))
+                   (string=? (call-with-input-file
+                                 (string-append profile "/etc/foo")
+                               get-string-all)
+                             "foo!"))))))
+
+(test-assertm "etc/profile when etc/ is a symlink"
+  ;; When etc/ is a symlink, the unsymlink code in 0.8.2 would fail
+  ;; gracelessly because 'scandir' would return #f.
+  (mlet* %store-monad
+      ((thing ->   (dummy-package "dummy"
+                     (build-system trivial-build-system)
+                     (arguments
+                      `(#:guile ,%bootstrap-guile
+                        #:builder
+                        (let ((out (assoc-ref %outputs "out")))
+                          (mkdir out)
+                          (mkdir (string-append out "/foo"))
+                          (symlink "foo" (string-append out "/etc"))
+                          (call-with-output-file (string-append out "/etc/bar")
+                            (lambda (port)
+                              (display "foo!" port))))))))
+       (entry ->   (package->manifest-entry thing))
+       (drv        (profile-derivation (manifest (list entry))
+                                       #:hooks '()))
+       (profile -> (derivation->output-path drv)))
+    (mbegin %store-monad
+      (built-derivations (list drv))
+      (return (and (file-exists? (string-append profile "/etc/profile"))
+                   (string=? (call-with-input-file
+                                 (string-append profile "/etc/bar")
+                               get-string-all)
+                             "foo!"))))))
+
 (test-end "profiles")
 
 
diff --git a/tests/publish.scm b/tests/publish.scm
new file mode 100644
index 0000000000..60f57a8ddb
--- /dev/null
+++ b/tests/publish.scm
@@ -0,0 +1,114 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 David Thompson <davet@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 (test-publish)
+  #:use-module (guix scripts publish)
+  #:use-module (guix tests)
+  #:use-module (guix config)
+  #:use-module (guix utils)
+  #:use-module (guix hash)
+  #:use-module (guix store)
+  #:use-module (guix base32)
+  #:use-module (guix base64)
+  #:use-module ((guix serialization) #:select (restore-file))
+  #:use-module (guix pk-crypto)
+  #:use-module (web client)
+  #:use-module (web response)
+  #:use-module (rnrs bytevectors)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
+  #:use-module (srfi srfi-64)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 rdelim))
+
+(define %store
+  (open-connection-for-tests))
+
+(define %reference (add-text-to-store %store "ref" "foo"))
+
+(define %item (add-text-to-store %store "item" "bar" (list %reference)))
+
+(define (http-get-body uri)
+  (call-with-values (lambda () (http-get uri))
+    (lambda (response body) body)))
+
+(define (publish-uri route)
+  (string-append "http://localhost:6789" route))
+
+;; Run a local publishing server in a separate thread.
+(call-with-new-thread
+ (lambda ()
+   (guix-publish "--port=6789"))) ; attempt to avoid port collision
+
+;; Wait until the server is accepting connections.
+(let ((conn (socket PF_INET SOCK_STREAM 0)))
+  (let loop ()
+    (unless (false-if-exception
+             (connect conn AF_INET (inet-pton AF_INET "127.0.0.1") 6789))
+      (loop))))
+
+(test-begin "publish")
+
+(test-equal "/nix-cache-info"
+  (format #f "StoreDir: ~a\nWantMassQuery: 0\nPriority: 100\n"
+          %store-directory)
+  (http-get-body (publish-uri "/nix-cache-info")))
+
+(test-equal "/*.narinfo"
+  (let* ((info (query-path-info %store %item))
+         (unsigned-info
+          (format #f
+                  "StorePath: ~a
+URL: nar/~a
+Compression: none
+NarHash: sha256:~a
+NarSize: ~d
+References: ~a~%"
+                  %item
+                  (basename %item)
+                  (bytevector->base32-string
+                   (path-info-hash info))
+                  (path-info-nar-size info)
+                  (basename (first (path-info-references info)))))
+         (signature (base64-encode
+                     (string->utf8
+                      (canonical-sexp->string
+                       ((@@ (guix scripts publish) signed-string)
+                        unsigned-info))))))
+    (format #f "~aSignature: 1;~a;~a~%"
+            unsigned-info (gethostname) signature))
+  (utf8->string
+   (http-get-body
+    (publish-uri
+     (string-append "/" (store-path-hash-part %item) ".narinfo")))))
+
+(test-equal "/nar/*"
+  "bar"
+  (call-with-temporary-output-file
+   (lambda (temp port)
+     (let ((nar (utf8->string
+                 (http-get-body
+                  (publish-uri
+                   (string-append "/nar/" (basename %item)))))))
+       (call-with-input-string nar (cut restore-file <> temp)))
+     (call-with-input-file temp read-string))))
+
+(test-end "publish")
+
+
+(exit (= (test-runner-fail-count (test-runner-current)) 0))
diff --git a/tests/store.scm b/tests/store.scm
index 9ed78be085..eeceed45c1 100644
--- a/tests/store.scm
+++ b/tests/store.scm
@@ -367,15 +367,15 @@
   (with-store s
     (let* ((d (package-derivation s %bootstrap-guile (%current-system)))
            (o (derivation->output-path d)))
-      ;; Create fake substituter data, to be read by `substitute-binary'.
+      ;; Create fake substituter data, to be read by 'guix substitute'.
       (with-derivation-narinfo d
         ;; Remove entry from the local cache.
         (false-if-exception
          (delete-file (string-append (getenv "XDG_CACHE_HOME")
-                                     "/guix/substitute-binary/"
+                                     "/guix/substitute/"
                                      (store-path-hash-part o))))
 
-        ;; Make sure `substitute-binary' correctly communicates the above
+        ;; Make sure 'guix substitute' correctly communicates the above
         ;; data.
         (set-build-options s #:use-substitutes? #t)
         (and (has-substitutes? s o)
@@ -439,7 +439,7 @@
       (with-derivation-substitute d c
         (sha256 => (make-bytevector 32 0)) ;select a hash that doesn't match C
 
-        ;; Make sure we use `substitute-binary'.
+        ;; Make sure we use 'guix substitute'.
         (set-build-options s
                            #:use-substitutes? #t
                            #:fallback? #f)
@@ -464,9 +464,9 @@
                  #:guile-for-build
                  (package-derivation s %bootstrap-guile (%current-system))))
            (o   (derivation->output-path d)))
-      ;; Create fake substituter data, to be read by `substitute-binary'.
+      ;; Create fake substituter data, to be read by 'guix substitute'.
       (with-derivation-narinfo d
-        ;; Make sure we use `substitute-binary'.
+        ;; Make sure we use 'guix substitute'.
         (set-build-options s #:use-substitutes? #t)
         (and (has-substitutes? s o)
              (guard (c ((nix-protocol-error? c)
@@ -606,6 +606,16 @@
          (file (add %store "foo" "Lowered.")))
     (call-with-input-file file get-string-all)))
 
+(test-assert "query-path-info"
+  (let* ((ref (add-text-to-store %store "ref" "foo"))
+         (item (add-text-to-store %store "item" "bar" (list ref)))
+         (info (query-path-info %store item)))
+    (and (equal? (path-info-references info) (list ref))
+         (equal? (path-info-hash info)
+                 (sha256
+                  (string->utf8
+                   (call-with-output-string (cut write-file item <>))))))))
+
 (test-end "store")
 
 
diff --git a/tests/substitute-binary.scm b/tests/substitute.scm
index 7c1204c1ab..85698127fa 100644
--- a/tests/substitute-binary.scm
+++ b/tests/substitute.scm
@@ -1,6 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2014 Nikita Karetnikov <nikita@karetnikov.org>
-;;; Copyright © 2014 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2014, 2015 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -17,8 +17,8 @@
 ;;; 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 (test-substitute-binary)
-  #:use-module (guix scripts substitute-binary)
+(define-module (test-substitute)
+  #:use-module (guix scripts substitute)
   #:use-module (guix base64)
   #:use-module (guix hash)
   #:use-module (guix serialization)
@@ -95,7 +95,7 @@ version identifier.."
 
 
 
-(test-begin "substitute-binary")
+(test-begin "substitute")
 
 (test-quit "not a number"
     "signature version"
@@ -132,7 +132,7 @@ a file for NARINFO."
                                                 "GUIX_BINARY_SUBSTITUTE_URL"))
                                   uri-path))
         (cache-directory   (string-append (getenv "XDG_CACHE_HOME")
-                                          "/guix/substitute-binary/")))
+                                          "/guix/substitute/")))
     (dynamic-wind
       (lambda ()
         (when (file-exists? cache-directory)
@@ -156,7 +156,7 @@ a file for NARINFO."
           (cute write-file
                 (string-append narinfo-directory "/example.out") <>))
 
-        (set! (@@ (guix scripts substitute-binary)
+        (set! (@@ (guix scripts substitute)
                   %allow-unauthenticated-substitutes?)
               #f))
       thunk
@@ -166,8 +166,8 @@ a file for NARINFO."
 (define-syntax-rule (with-narinfo narinfo body ...)
   (call-with-narinfo narinfo (lambda () body ...)))
 
-;; Transmit these options to 'guix substitute-binary'.
-(set! (@@ (guix scripts substitute-binary) %cache-url)
+;; Transmit these options to 'guix substitute'.
+(set! (@@ (guix scripts substitute) %cache-url)
       (getenv "GUIX_BINARY_SUBSTITUTE_URL"))
 
 (test-equal "query narinfo without signature"
@@ -180,7 +180,7 @@ a file for NARINFO."
          (with-input-from-string (string-append "have " (%store-prefix)
                                                 "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
            (lambda ()
-             (guix-substitute-binary "--query"))))))))
+             (guix-substitute "--query"))))))))
 
 (test-equal "query narinfo with invalid hash"
   ;; The hash in the signature differs from the hash of %NARINFO.
@@ -195,7 +195,7 @@ a file for NARINFO."
          (with-input-from-string (string-append "have " (%store-prefix)
                                                 "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
            (lambda ()
-             (guix-substitute-binary "--query"))))))))
+             (guix-substitute "--query"))))))))
 
 (test-equal "query narinfo signed with authorized key"
   (string-append (%store-prefix) "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
@@ -209,7 +209,7 @@ a file for NARINFO."
          (with-input-from-string (string-append "have " (%store-prefix)
                                                 "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
            (lambda ()
-             (guix-substitute-binary "--query"))))))))
+             (guix-substitute "--query"))))))))
 
 (test-equal "query narinfo signed with unauthorized key"
   ""                                              ; not substitutable
@@ -225,15 +225,15 @@ a file for NARINFO."
          (with-input-from-string (string-append "have " (%store-prefix)
                                                 "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
            (lambda ()
-             (guix-substitute-binary "--query"))))))))
+             (guix-substitute "--query"))))))))
 
 (test-quit "substitute, no signature"
     "lacks a signature"
   (with-narinfo %narinfo
-    (guix-substitute-binary "--substitute"
-                            (string-append (%store-prefix)
-                                           "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
-                            "foo")))
+    (guix-substitute "--substitute"
+                     (string-append (%store-prefix)
+                                    "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
+                     "foo")))
 
 (test-quit "substitute, invalid hash"
     "hash"
@@ -241,10 +241,10 @@ a file for NARINFO."
   (with-narinfo (string-append %narinfo "Signature: "
                                (signature-field "different body")
                                "\n")
-    (guix-substitute-binary "--substitute"
-                            (string-append (%store-prefix)
-                                           "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
-                            "foo")))
+    (guix-substitute "--substitute"
+                     (string-append (%store-prefix)
+                                    "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
+                     "foo")))
 
 (test-quit "substitute, unauthorized key"
     "unauthorized"
@@ -253,10 +253,10 @@ a file for NARINFO."
                                 %narinfo
                                 #:public-key %wrong-public-key)
                                "\n")
-    (guix-substitute-binary "--substitute"
-                            (string-append (%store-prefix)
-                                           "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
-                            "foo")))
+    (guix-substitute "--substitute"
+                     (string-append (%store-prefix)
+                                    "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
+                     "foo")))
 
 (test-equal "substitute, authorized key"
   "Substitutable data."
@@ -265,15 +265,15 @@ a file for NARINFO."
     (dynamic-wind
       (const #t)
       (lambda ()
-        (guix-substitute-binary "--substitute"
-                                (string-append (%store-prefix)
-                                               "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
-                                "substitute-retrieved")
+        (guix-substitute "--substitute"
+                         (string-append (%store-prefix)
+                                        "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
+                         "substitute-retrieved")
         (call-with-input-file "substitute-retrieved" get-string-all))
       (lambda ()
         (false-if-exception (delete-file "substitute-retrieved"))))))
 
-(test-end "substitute-binary")
+(test-end "substitute")
 
 
 (exit (= (test-runner-fail-count (test-runner-current)) 0))
diff --git a/tests/syscalls.scm b/tests/syscalls.scm
index f26331e164..706f3dff44 100644
--- a/tests/syscalls.scm
+++ b/tests/syscalls.scm
@@ -19,6 +19,7 @@
 (define-module (test-syscalls)
   #:use-module (guix build syscalls)
   #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
   #:use-module (srfi srfi-64)
   #:use-module (ice-9 match))
 
@@ -45,7 +46,10 @@
       (memv (system-error-errno args) (list EPERM ENOENT)))))
 
 (test-assert "mount-points"
-  (member "/" (mount-points)))
+  ;; Reportedly "/" is not always listed as a mount point, so check a few
+  ;; others (see <http://bugs.gnu.org/20261>.)
+  (any (cute member <> (mount-points))
+       '("/" "/proc" "/sys" "/dev")))
 
 (test-assert "swapon, ENOENT/EPERM"
   (catch 'system-error
diff --git a/tests/utils.scm b/tests/utils.scm
index a662c9a8d3..115868c857 100644
--- a/tests/utils.scm
+++ b/tests/utils.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
 ;;;
 ;;; This file is part of GNU Guix.
@@ -21,6 +21,7 @@
   #:use-module ((guix config) #:select (%gzip))
   #:use-module (guix utils)
   #:use-module ((guix store) #:select (%store-prefix store-path-package-name))
+  #:use-module ((guix search-paths) #:select (string-tokenize*))
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-11)
   #:use-module (srfi srfi-64)