diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/boot-parameters.scm | 2 | ||||
-rw-r--r-- | tests/channels.scm | 47 | ||||
-rw-r--r-- | tests/egg.scm | 132 | ||||
-rw-r--r-- | tests/gexp.scm | 31 | ||||
-rw-r--r-- | tests/git.scm | 28 | ||||
-rw-r--r-- | tests/gnu-maintenance.scm | 3 | ||||
-rw-r--r-- | tests/go.scm | 142 | ||||
-rw-r--r-- | tests/grafts.scm | 83 | ||||
-rw-r--r-- | tests/graph.scm | 21 | ||||
-rw-r--r-- | tests/guix-package.sh | 2 | ||||
-rw-r--r-- | tests/guix-system.sh | 14 | ||||
-rw-r--r-- | tests/hackage.scm | 51 | ||||
-rw-r--r-- | tests/import-git.scm | 245 | ||||
-rw-r--r-- | tests/import-utils.scm | 28 | ||||
-rw-r--r-- | tests/inferior.scm | 26 | ||||
-rw-r--r-- | tests/lint.scm | 267 | ||||
-rw-r--r-- | tests/minetest.scm | 382 | ||||
-rw-r--r-- | tests/opam.scm | 32 | ||||
-rw-r--r-- | tests/pack.scm | 94 | ||||
-rw-r--r-- | tests/packages.scm | 11 | ||||
-rw-r--r-- | tests/profiles.scm | 57 | ||||
-rw-r--r-- | tests/publish.scm | 32 | ||||
-rw-r--r-- | tests/pypi.scm | 106 | ||||
-rw-r--r-- | tests/records.scm | 56 | ||||
-rw-r--r-- | tests/services/configuration.scm | 120 | ||||
-rw-r--r-- | tests/services/telephony.scm | 446 | ||||
-rw-r--r-- | tests/snix.scm | 73 | ||||
-rw-r--r-- | tests/store.scm | 72 | ||||
-rw-r--r-- | tests/system.scm | 4 | ||||
-rw-r--r-- | tests/transformations.scm | 51 |
30 files changed, 2478 insertions, 180 deletions
diff --git a/tests/boot-parameters.scm b/tests/boot-parameters.scm index 3deae564c4..b2799d0596 100644 --- a/tests/boot-parameters.scm +++ b/tests/boot-parameters.scm @@ -81,7 +81,7 @@ (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/sda"))) + (targets '("/dev/sda")))) (file-systems (cons* (file-system (device %default-root-device) (mount-point %root-path) diff --git a/tests/channels.scm b/tests/channels.scm index 0264369d9e..3e82315b0c 100644 --- a/tests/channels.scm +++ b/tests/channels.scm @@ -408,6 +408,53 @@ '(#f "tag-for-first-news-entry"))))))) (unless (which (git-command)) (test-skip 1)) +(test-assert "channel-news, annotated tag" + (with-temporary-git-repository directory + `((add ".guix-channel" + ,(object->string + '(channel (version 0) + (news-file "news.scm")))) + (add "src/a.txt" "A") + (commit "first commit") + (tag "tag-for-first-news-entry" + "This is an annotated tag.") + (add "news.scm" + ,(lambda (repository) + (let ((previous + (reference-name->oid repository "HEAD"))) + (object->string + `(channel-news + (version 0) + (entry (tag "tag-for-first-news-entry") + (title (en "New file!")) + (body (en "Yeah, a.txt.")))))))) + (commit "second commit")) + (with-repository directory repository + (define (find-commit* message) + (oid->string (commit-id (find-commit repository message)))) + + (let ((channel (channel (url (string-append "file://" directory)) + (name 'foo))) + (commit1 (find-commit* "first commit")) + (commit2 (find-commit* "second commit"))) + (and (null? (channel-news-for-commit channel commit1)) + (lset= equal? + (map channel-news-entry-title + (channel-news-for-commit channel commit2)) + '((("en" . "New file!")))) + (lset= string=? + (map channel-news-entry-tag + (channel-news-for-commit channel commit2)) + (list "tag-for-first-news-entry")) + ;; This is an annotated tag, but 'channel-news-entry-commit' + ;; should give us the commit ID, not the ID of the annotated tag + ;; object. + (lset= string=? + (map channel-news-entry-commit + (channel-news-for-commit channel commit2)) + (list commit1))))))) + +(unless (which (git-command)) (test-skip 1)) (test-assert "latest-channel-instances, missing introduction for 'guix'" (with-temporary-git-repository directory '((add "a.txt" "A") diff --git a/tests/egg.scm b/tests/egg.scm new file mode 100644 index 0000000000..0884d8d429 --- /dev/null +++ b/tests/egg.scm @@ -0,0 +1,132 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz> +;;; +;;; 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-eggs) + #:use-module (guix import egg) + #:use-module (guix gexp) + #:use-module (guix base32) + #:use-module (gcrypt hash) + #:use-module (guix tests) + #:use-module ((guix build syscalls) #:select (mkdtemp!)) + #:use-module ((guix build utils) #:select (delete-file-recursively mkdir-p which)) + #:use-module ((guix utils) #:select (call-with-temporary-output-file)) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-64) + #:use-module (web uri) + #:use-module (ice-9 match)) + +(define test-egg-1 + '((synopsis "Example egg") + (license "GPL-3/MIT") + (version "1.0.0") + (test-dependencies test srfi-1) + (foreign-dependencies libgit2) + (build-dependencies begin-syntax) + (dependencies datatype) + (author "John Doe"))) + +(define test-egg-2 + '((synopsis "Example egg") + (license "GPL-3+") + (version "0.3") + (test-dependencies test) + (foreign-dependencies libgit2) + (build-dependencies begin-syntax) + (dependencies datatype) + (author "Alice Bobson"))) + +(define test-egg-1-file "/tmp/guix-egg-1") +(define test-egg-2-file "/tmp/guix-egg-2") + +(test-begin "egg") + +(test-equal "guix-package->egg-name" + "bar" + (guix-package->egg-name + (dummy-package "dummy" + (name "chicken-bar")))) + +;; Copied from tests/hackage.scm +(define-syntax-rule (define-package-matcher name pattern) + (define* (name obj) + (match obj + (pattern #t) + (x (pk 'fail x #f))))) + +(define (eval-test-with-egg-file egg-name egg-test egg-file matcher) + (call-with-output-file egg-file + (lambda (port) + (write egg-test port))) + (matcher (egg->guix-package egg-name + #:file egg-file + #:source (plain-file + (string-append egg-name "-egg") + "content")))) + +(define-package-matcher match-chicken-foo + ('package + ('name "chicken-foo") + ('version "1.0.0") + ('source (? file-like? source)) + ('build-system 'chicken-build-system) + ('arguments ('quasiquote ('#:egg-name "foo"))) + ('native-inputs + ('quasiquote + (("chicken-test" ('unquote chicken-test)) + ("chicken-srfi-1" ('unquote chicken-srfi-1)) + ("chicken-begin-syntax" ('unquote chicken-begin-syntax))))) + ('inputs + ('quasiquote + (("libgit2" ('unquote libgit2))))) + ('propagated-inputs + ('quasiquote + (("chicken-datatype" ('unquote chicken-datatype))))) + ('home-page "https://wiki.call-cc.org/egg/foo") + ('synopsis "Example egg") + ('description #f) + ('license '(list license:gpl3 license:expat)))) + +(define-package-matcher match-chicken-bar + ('package + ('name "chicken-bar") + ('version "0.3") + ('source (? file-like? source)) + ('build-system 'chicken-build-system) + ('arguments ('quasiquote ('#:egg-name "bar"))) + ('native-inputs + ('quasiquote + (("chicken-test" ('unquote chicken-test)) + ("chicken-begin-syntax" ('unquote chicken-begin-syntax))))) + ('inputs + ('quasiquote + (("libgit2" ('unquote libgit2))))) + ('propagated-inputs + ('quasiquote + (("chicken-datatype" ('unquote chicken-datatype))))) + ('home-page "https://wiki.call-cc.org/egg/bar") + ('synopsis "Example egg") + ('description #f) + ('license 'license:gpl3+))) + +(test-assert "egg->guix-package local file, multiple licenses" + (eval-test-with-egg-file "foo" test-egg-1 test-egg-1-file match-chicken-foo)) + +(test-assert "egg->guix-package local file, single license" + (eval-test-with-egg-file "bar" test-egg-2 test-egg-2-file match-chicken-bar)) + +(test-end "egg") diff --git a/tests/gexp.scm b/tests/gexp.scm index 834e78b9a0..39a47d4e8c 100644 --- a/tests/gexp.scm +++ b/tests/gexp.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be> ;;; ;;; This file is part of GNU Guix. ;;; @@ -89,6 +90,36 @@ (test-begin "gexp") +(test-equal "no references" + '(display "hello gexp->approximate-sexp!") + (gexp->approximate-sexp #~(display "hello gexp->approximate-sexp!"))) + +(test-equal "unquoted gexp" + '(display "hello") + (let ((inside #~"hello")) + (gexp->approximate-sexp #~(display #$inside)))) + +(test-equal "unquoted gexp (native)" + '(display "hello") + (let ((inside #~"hello")) + (gexp->approximate-sexp #~(display #+inside)))) + +(test-equal "spliced gexp" + '(display '(fresh vegetables)) + (let ((inside #~(fresh vegetables))) + (gexp->approximate-sexp #~(display '(#$@inside))))) + +(test-equal "unspliced gexp, approximated" + ;; (*approximate*) is really an implementation detail + '(display '(*approximate*)) + (let ((inside (file-append coreutils "/bin/hello"))) + (gexp->approximate-sexp #~(display '(#$@inside))))) + +(test-equal "unquoted gexp, approximated" + '(display '(*approximate*)) + (let ((inside (file-append coreutils "/bin/hello"))) + (gexp->approximate-sexp #~(display '#$inside)))) + (test-equal "no refs" '(display "hello!") (let ((exp (gexp (display "hello!")))) diff --git a/tests/git.scm b/tests/git.scm index aa4f03ca62..d0646bbc85 100644 --- a/tests/git.scm +++ b/tests/git.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2019, 2020 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz ;;; ;;; This file is part of GNU Guix. ;;; @@ -161,4 +162,31 @@ (commit-relation master1 merge) (commit-relation merge master1)))))) +(unless (which (git-command)) (test-skip 1)) +(test-equal "remote-refs" + '("refs/heads/develop" "refs/heads/master" + "refs/tags/v1.0" "refs/tags/v1.1") + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "v1.0" "release-1.0") + (branch "develop") + (checkout "develop") + (add "b.txt" "B") + (commit "Second commit") + (tag "v1.1" "release-1.1")) + (remote-refs directory))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "remote-refs: only tags" + '("refs/tags/v1.0" "refs/tags/v1.1") + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "v1.0" "Release 1.0") + (add "b.txt" "B") + (commit "Second commit") + (tag "v1.1" "Release 1.1")) + (remote-refs directory #:tags? #t))) + (test-end "git") diff --git a/tests/gnu-maintenance.scm b/tests/gnu-maintenance.scm index 837b80063a..c04d8ba733 100644 --- a/tests/gnu-maintenance.scm +++ b/tests/gnu-maintenance.scm @@ -34,7 +34,8 @@ ("mediainfo" "mediainfo_20.09.tar.xz") ("exiv2" "exiv2-0.27.3-Source.tar.gz") ("mpg321" "mpg321_0.3.2.orig.tar.gz") - ("bvi" "bvi-1.4.1.src.tar.gz"))) + ("bvi" "bvi-1.4.1.src.tar.gz") + ("hostscope" "hostscope-V2.1.tgz"))) (every (lambda (project+file) (not (apply release-file? project+file))) '(("guile" "guile-www-1.1.1.tar.gz") diff --git a/tests/go.scm b/tests/go.scm index e5780e68b0..a70a0ddbf5 100644 --- a/tests/go.scm +++ b/tests/go.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2021 François Joulaud <francois.joulaud@radiofrance.com> +;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev> ;;; ;;; This file is part of GNU Guix. ;;; @@ -31,6 +32,9 @@ #:use-module (srfi srfi-64) #:use-module (web response)) +(define go.mod-requirements + (@@ (guix import go) go.mod-requirements)) + (define parse-go.mod (@@ (guix import go) parse-go.mod)) @@ -57,7 +61,6 @@ require ( exclude D v1.2.3 ") - (define fixture-go-mod-complete "module M @@ -96,11 +99,40 @@ replace ( ") +(define fixture-go-mod-unparsable + "module my/thing +go 1.12 // avoid feature X +require other/thing v1.0.2 +// Security issue: CVE-XXXXX +exclude old/thing v1.2.3 +new-directive another/thing yet-another/thing +replace ( + bad/thing v1.4.5 => good/thing v1.4.5 + // Unparseable + bad/thing [v1.4.5, v1.9.7] => good/thing v2.0.0 +) +") +(define fixture-go-mod-retract + "retract v0.9.1 -(define fixture-latest-for-go-check - "{\"Version\":\"v0.0.0-20201130134442-10cb98267c6c\",\"Time\":\"2020-11-30T13:44:42Z\"}") +retract ( + v1.9.2 + [v1.0.0, v1.7.9] +) +") +(define fixture-go-mod-strings + "require `example.com/\"some-repo\"` v1.9.3 +require ( + `example.com/\"another.repo\"` v1.0.0 + \"example.com/special!repo\" v9.3.1 +) +replace \"example.com/\\\"some-repo\\\"\" => `launchpad.net/some-repo` v1.9.3 +replace ( + \"example.com/\\\"another.repo\\\"\" => launchpad.net/another-repo v1.0.0 +) +") (define fixtures-go-check-test (let ((version @@ -158,15 +190,11 @@ require github.com/kr/pretty v0.2.1 "v1.0.2" (go-version->git-ref "v1.0.2")) -(test-equal "go-version omited 'v' character" - "v1.0.2" - (go-version->git-ref "v1.0.2")) - -(test-equal "go-version with embeded git-ref" +(test-equal "go-version with embedded git-ref" "65e3620a7ae7" (go-version->git-ref "v0.0.0-20190821162956-65e3620a7ae7")) -(test-equal "go-version with complex embeded git-ref" +(test-equal "go-version with complex embedded git-ref" "daa7c04131f5" (go-version->git-ref "v1.2.4-0.20191109021931-daa7c04131f5")) @@ -189,7 +217,7 @@ require github.com/kr/pretty v0.2.1 (string<? (car p1) (car p2))) (test-equal name (sort expected inf?) - (sort ((@@ (guix import go) parse-go.mod) input) inf?))) + (sort (go.mod-requirements (parse-go.mod input)) inf?))) (testing-parse-mod "parse-go.mod-simple" '(("good/thing" "v1.4.5") @@ -225,6 +253,98 @@ require github.com/kr/pretty v0.2.1 ("github.com/go-check/check" "v0.0.0-20140225173054-eb6ee6f84d0a")) fixture-go-mod-complete) +(test-equal "parse-go.mod: simple" + `((module (module-path "my/thing")) + (go (version "1.12")) + (require (module-path "other/thing") (version "v1.0.2")) + (require (module-path "new/thing/v2") (version "v2.3.4")) + (exclude (module-path "old/thing") (version "v1.2.3")) + (replace (original (module-path "bad/thing") (version "v1.4.5")) + (with (module-path "good/thing") (version "v1.4.5")))) + (parse-go.mod fixture-go-mod-simple)) + +(test-equal "parse-go.mod: comments and unparsable lines" + `((module (module-path "my/thing")) + (go (version "1.12") (comment "avoid feature X")) + (require (module-path "other/thing") (version "v1.0.2")) + (comment "Security issue: CVE-XXXXX") + (exclude (module-path "old/thing") (version "v1.2.3")) + (unknown "new-directive another/thing yet-another/thing") + (replace (original (module-path "bad/thing") (version "v1.4.5")) + (with (module-path "good/thing") (version "v1.4.5"))) + (comment "Unparseable") + (unknown "bad/thing [v1.4.5, v1.9.7] => good/thing v2.0.0")) + (parse-go.mod fixture-go-mod-unparsable)) + +(test-equal "parse-go.mod: retract" + `((retract (version "v0.9.1")) + (retract (version "v1.9.2")) + (retract (range (version "v1.0.0") (version "v1.7.9")))) + (parse-go.mod fixture-go-mod-retract)) + +(test-equal "parse-go.mod: raw strings and quoted strings" + `((require (module-path "example.com/\"some-repo\"") (version "v1.9.3")) + (require (module-path "example.com/\"another.repo\"") (version "v1.0.0")) + (require (module-path "example.com/special!repo") (version "v9.3.1")) + (replace (original (module-path "example.com/\"some-repo\"")) + (with (module-path "launchpad.net/some-repo") (version "v1.9.3"))) + (replace (original (module-path "example.com/\"another.repo\"")) + (with (module-path "launchpad.net/another-repo") (version "v1.0.0")))) + (parse-go.mod fixture-go-mod-strings)) + +(test-equal "parse-go.mod: complete" + `((module (module-path "M")) + (go (version "1.13")) + (replace (original (module-path "github.com/myname/myproject/myapi")) + (with (file-path "./api"))) + (replace (original (module-path "github.com/mymname/myproject/thissdk")) + (with (file-path "../sdk"))) + (replace (original (module-path "launchpad.net/gocheck")) + (with (module-path "github.com/go-check/check") + (version "v0.0.0-20140225173054-eb6ee6f84d0a"))) + (require (module-path "github.com/user/project") + (version "v1.1.11")) + (require (module-path "github.com/user/project/sub/directory") + (version "v1.1.12")) + (require (module-path "bitbucket.org/user/project") + (version "v1.11.20")) + (require (module-path "bitbucket.org/user/project/sub/directory") + (version "v1.11.21")) + (require (module-path "launchpad.net/project") + (version "v1.1.13")) + (require (module-path "launchpad.net/project/series") + (version "v1.1.14")) + (require (module-path "launchpad.net/project/series/sub/directory") + (version "v1.1.15")) + (require (module-path "launchpad.net/~user/project/branch") + (version "v1.1.16")) + (require (module-path "launchpad.net/~user/project/branch/sub/directory") + (version "v1.1.17")) + (require (module-path "hub.jazz.net/git/user/project") + (version "v1.1.18")) + (require (module-path "hub.jazz.net/git/user/project/sub/directory") + (version "v1.1.19")) + (require (module-path "k8s.io/kubernetes/subproject") + (version "v1.1.101")) + (require (module-path "one.example.com/abitrary/repo") + (version "v1.1.111")) + (require (module-path "two.example.com/abitrary/repo") + (version "v0.0.2")) + (require (module-path "quoted.example.com/abitrary/repo") + (version "v0.0.2")) + (replace (original (module-path "two.example.com/abitrary/repo")) + (with (module-path "github.com/corp/arbitrary-repo") + (version "v0.0.2"))) + (replace (original (module-path "golang.org/x/sys")) + (with (module-path "golang.org/x/sys") + (version "v0.0.0-20190813064441-fde4db37ae7a")) + (comment "pinned to release-branch.go1.13")) + (replace (original (module-path "golang.org/x/tools")) + (with (module-path "golang.org/x/tools") + (version "v0.0.0-20190821162956-65e3620a7ae7")) + (comment "pinned to release-branch.go1.13"))) + (parse-go.mod fixture-go-mod-complete)) + ;;; End-to-end tests for (guix import go) (define (mock-http-fetch testcase) (lambda (url . rest) @@ -290,6 +410,6 @@ package.") (nix-base32-string->bytevector "0sjjj9z1dhilhpc8pq4154czrb79z9cm044jvn75kxcjv6v5l2m5") #f))) - (go-module->guix-package "github.com/go-check/check"))))))) + (go-module->guix-package* "github.com/go-check/check"))))))) (test-end "go") diff --git a/tests/grafts.scm b/tests/grafts.scm index a12c6a5911..7e1959e4a7 100644 --- a/tests/grafts.scm +++ b/tests/grafts.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2021 Mark H Weaver <mhw@netris.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -468,4 +469,86 @@ replacement "/gnu/store"))))) +(define (insert-nuls char-size str) + (string-join (map string (string->list str)) + (make-string (- char-size 1) #\nul))) + +(define (nuls-to-underscores s) + (string-replace-substring s "\0" "_")) + +(define (annotate-buffer-boundary s) + (string-append (string-take s buffer-size) + "|" + (string-drop s buffer-size))) + +(define (abbreviate-leading-fill s) + (let ((s* (string-trim s #\=))) + (format #f "[~a =s]~a" + (- (string-length s) + (string-length s*)) + s*))) + +(define (prettify-for-display s) + (abbreviate-leading-fill + (annotate-buffer-boundary + (nuls-to-underscores s)))) + +(define (two-sample-refs-with-gap char-size1 char-size2 gap offset + char1 name1 char2 name2) + (string-append + (make-string (- buffer-size offset) #\=) + (insert-nuls char-size1 + (string-append "/gnu/store/" (make-string 32 char1) name1)) + gap + (insert-nuls char-size2 + (string-append "/gnu/store/" (make-string 32 char2) name2)) + (list->string (map integer->char (iota 77 33))))) + +(define (sample-map-entry old-char new-char new-name) + (cons (make-string 32 old-char) + (string->utf8 (string-append (make-string 32 new-char) + new-name)))) + +(define (test-two-refs-with-gap char-size1 char-size2 gap offset) + (test-equal + (format #f "test-two-refs-with-gap, char-sizes ~a ~a, gap ~s, offset ~a" + char-size1 char-size2 gap offset) + (prettify-for-display + (two-sample-refs-with-gap char-size1 char-size2 gap offset + #\6 "-BlahBlaH" + #\8"-SoMeTHiNG")) + (prettify-for-display + (let* ((content (two-sample-refs-with-gap char-size1 char-size2 gap offset + #\5 "-blahblah" + #\7 "-something")) + (replacement (alist->vhash + (list (sample-map-entry #\5 #\6 "-BlahBlaH") + (sample-map-entry #\7 #\8 "-SoMeTHiNG"))))) + (call-with-output-string + (lambda (output) + ((@@ (guix build graft) replace-store-references) + (open-input-string content) output + replacement + "/gnu/store"))))))) + +(for-each (lambda (char-size1) + (for-each (lambda (char-size2) + (for-each (lambda (gap) + (for-each (lambda (offset) + (test-two-refs-with-gap char-size1 + char-size2 + gap + offset)) + ;; offsets to test + (map (lambda (i) + (+ i (* 40 char-size1))) + (iota 30)))) + ;; gaps + '("" "-" " " "a"))) + ;; char-size2 values to test + '(1 2))) + ;; char-size1 values to test + '(1 2 4)) + + (test-end) diff --git a/tests/graph.scm b/tests/graph.scm index e374dad1a5..fadac265f9 100644 --- a/tests/graph.scm +++ b/tests/graph.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -94,6 +94,25 @@ edges." (list p3 p3 p2) (list p2 p1 p1)))))))) +(test-assert "package DAG, limited depth" + (let-values (((backend nodes+edges) (make-recording-backend))) + (let* ((p1 (dummy-package "p1")) + (p2 (dummy-package "p2" (inputs `(("p1" ,p1))))) + (p3 (dummy-package "p3" (inputs `(("p1" ,p1))))) + (p4 (dummy-package "p4" (inputs `(("p2" ,p2) ("p3" ,p3)))))) + (run-with-store %store + (export-graph (list p4) 'port + #:max-depth 1 + #:node-type %package-node-type + #:backend backend)) + ;; We should see nothing more than these 3 packages. + (let-values (((nodes edges) (nodes+edges))) + (and (equal? nodes (map package->tuple (list p4 p2 p3))) + (equal? edges + (map edge->tuple + (list p4 p4) + (list p2 p3)))))))) + (test-assert "reverse package DAG" (let-values (((backend nodes+edges) (make-recording-backend))) (run-with-store %store diff --git a/tests/guix-package.sh b/tests/guix-package.sh index 39e2b514c3..92ab565c5b 100644 --- a/tests/guix-package.sh +++ b/tests/guix-package.sh @@ -459,7 +459,7 @@ if guix package --bootstrap -n -m "$module_dir/manifest.scm" \ then false else cat "$module_dir/stderr" - grep "manifest.scm:[1-3]:.*wonderful-package.*: unbound variable" \ + grep "manifest.scm:[1-4]:.*wonderful-package.*: unbound variable" \ "$module_dir/stderr" fi diff --git a/tests/guix-system.sh b/tests/guix-system.sh index 238c8929a8..6aab1f380a 100644 --- a/tests/guix-system.sh +++ b/tests/guix-system.sh @@ -51,6 +51,7 @@ then # This must not succeed. exit 1 else + cat "$errorfile" grep "$tmpfile:2:3:.*missing.* initializers" "$errorfile" fi @@ -66,7 +67,12 @@ then # This must not succeed. exit 1 else - grep "$tmpfile:4:1: missing closing paren" "$errorfile" + cat "$errorfile" + + # Guile 3.0.6 gets line/column numbers for 'read-error' wrong + # (zero-indexed): <https://bugs.gnu.org/48089>. + grep "$tmpfile:4:1: missing closing paren" "$errorfile" || \ + grep "$tmpfile:3:0: missing closing paren" "$errorfile" fi @@ -109,7 +115,7 @@ cat > "$tmpfile" <<EOF (timezone "Europe/Paris") ; 6 (locale "en_US.UTF-8") ; 7 - (bootloader (GRUB-config (target "/dev/sdX"))) ; 9 + (bootloader (GRUB-config (targets (list "/dev/sdX")))) ; 9 (file-systems (cons (file-system (device (file-system-label "root")) (mount-point "/") @@ -162,7 +168,7 @@ OS_BASE=' (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/sdX"))) + (targets (list "/dev/sdX")))) (file-systems (cons (file-system (device (file-system-label "root")) (mount-point "/") @@ -235,7 +241,7 @@ make_user_config () (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/sdX"))) + (targets (list "/dev/sdX")))) (file-systems (cons (file-system (device (file-system-label "root")) (mount-point "/") diff --git a/tests/hackage.scm b/tests/hackage.scm index 77e333cbfc..aca807027c 100644 --- a/tests/hackage.scm +++ b/tests/hackage.scm @@ -1,6 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch> ;;; Copyright © 2019 Robert Vollmert <rob@vllmrt.net> +;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz> ;;; ;;; This file is part of GNU Guix. ;;; @@ -183,7 +184,7 @@ library ('home-page "http://test.org") ('synopsis (? string?)) ('description (? string?)) - ('license 'bsd-3))) + ('license 'license:bsd-3))) (define* (eval-test-with-cabal test-cabal matcher #:key (cabal-environment '())) (define port (open-input-string test-cabal)) @@ -232,7 +233,7 @@ library ('home-page "http://test.org") ('synopsis (? string?)) ('description (? string?)) - ('license 'bsd-3))) + ('license 'license:bsd-3))) (test-assert "hackage->guix-package test 6" (eval-test-with-cabal test-cabal-6 match-ghc-foo-6)) @@ -317,8 +318,6 @@ executable cabal mtl >= 2.0 && < 3 ") -;; Fails: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=25138 -(test-expect-fail 1) (test-assert "hackage->guix-package test flag executable" (eval-test-with-cabal test-cabal-flag-executable match-ghc-foo)) @@ -362,7 +361,7 @@ executable cabal ('home-page "http://test.org") ('synopsis (? string?)) ('description (? string?)) - ('license 'bsd-3))) + ('license 'license:bsd-3))) (test-assert "hackage->guix-package test cabal revision" (eval-test-with-cabal test-cabal-revision match-ghc-foo-revision)) @@ -387,4 +386,46 @@ executable cabal #t) (x (pk 'fail x #f)))) +(define test-cabal-import + "name: foo +version: 1.0.0 +homepage: http://test.org +synopsis: synopsis +description: description +license: BSD3 +common commons + build-depends: + HTTP >= 4000.2.5 && < 4000.3, + mtl >= 2.0 && < 3 + +executable cabal + import: commons +") + +(define-package-matcher match-ghc-foo-import + ('package + ('name "ghc-foo") + ('version "1.0.0") + ('source + ('origin + ('method 'url-fetch) + ('uri ('string-append + "https://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))))) + ('home-page "http://test.org") + ('synopsis (? string?)) + ('description (? string?)) + ('license 'license:bsd-3))) + +(test-assert "hackage->guix-package test cabal import" + (eval-test-with-cabal test-cabal-import match-ghc-foo-import)) + (test-end "hackage") diff --git a/tests/import-git.scm b/tests/import-git.scm new file mode 100644 index 0000000000..f1bce154bb --- /dev/null +++ b/tests/import-git.scm @@ -0,0 +1,245 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz +;;; +;;; 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-import-git) + #:use-module (git) + #:use-module (guix git) + #:use-module (guix tests) + #:use-module (guix packages) + #:use-module (guix import git) + #:use-module (guix git-download) + #:use-module (guix tests git) + #:use-module (guix build utils) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-64)) + +;; Test the (guix import git) tools. + +(test-begin "git") + +(define* (make-package directory version #:optional (properties '())) + (dummy-package "test-package" + (version version) + (properties properties) + (source + (origin + (method git-fetch) + (uri (git-reference + (url (string-append "file://" directory)) + (commit version))) + (sha256 + (base32 + "0000000000000000000000000000000000000000000000000000")))))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: no custom prefix, suffix, and delimiter" + "1.0.1" + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "1.0.1" "Release 1.0.1")) + (let ((package (make-package directory "1.0.0"))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: custom prefix, no suffix and delimiter" + "1.0.1" + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "prefix-1.0.1" "Release 1.0.1")) + (let ((package (make-package directory "1.0.0" + '((release-tag-prefix . "prefix-"))))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: custom suffix, no prefix and delimiter" + "1.0.1" + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "1.0.1-suffix-123" "Release 1.0.1")) + (let ((package (make-package directory "1.0.0" + '((release-tag-suffix . "-suffix-[0-9]*"))))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: custom delimiter, no prefix and suffix" + "2021.09.07" + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "2021-09-07" "Release 2021-09-07")) + (let ((package (make-package directory "2021-09-06" + '((release-tag-version-delimiter . "-"))))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: empty delimiter, no prefix and suffix" + "20210907" + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "20210907" "Release 20210907")) + (let ((package (make-package directory "20210906" + '((release-tag-version-delimiter . ""))))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: custom prefix and suffix, no delimiter" + "2.0.0" + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "Release-2.0.0suffix-1" "Release 2.0.0")) + (let ((package (make-package directory "1.0.0" + '((release-tag-prefix . "Release-") + (release-tag-suffix . "suffix-[0-9]"))))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: custom prefix, suffix, and delimiter" + "2.0.0" + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "Release-2_0_0suffix-1" "Release 2.0.0")) + (let ((package (make-package directory "1.0.0" + '((release-tag-prefix . "Release-") + (release-tag-suffix . "suffix-[0-9]") + (release-tag-version-delimiter . "_"))))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: only pre-releases available" + #f + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "2.0.0-rc1" "Release candidate for 2.0.0")) + (let ((package (make-package directory "1.0.0"))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: accept pre-releases" + "2.0.0-rc1" + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "2.0.0-rc1" "Release candidate for 2.0.0")) + (let ((package (make-package directory "1.0.0" + '((accept-pre-releases? . #t))))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: accept pre-releases, and custom prefix" + "2.0.0-rc1" + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "version-2.0.0-rc1" "Release candidate for 2.0.0")) + (let ((package (make-package directory "1.0.0" + '((accept-pre-releases? . #t) + (release-tag-prefix . "version-"))))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: accept pre-releases, and custom suffix" + "2.0.0-rc1" + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "2.0.0-rc1-suffix" "Release candidate for 2.0.0")) + (let ((package (make-package directory "1.0.0" + '((accept-pre-releases? . #t) + (release-tag-suffix . "-suffix"))))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: accept pre-releases, delimiter conflicts with pre-release part" + "2.0.0_alpha" + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "2_0_0_alpha" "Alpha release for 2.0.0")) + (let ((package (make-package directory "1.0.0" + '((accept-pre-releases? . #t) + (release-tag-version-delimiter . "_"))))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: accept pre-releases, and custom suffix and prefix" + "2.0.0-alpha" + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "prefix123-2.0.0-alpha-suffix" "Alpha release for 2.0.0")) + (let ((package (make-package directory "1.0.0" + '((accept-pre-releases? . #t) + (release-tag-prefix . "prefix[0-9]{3}-") + (release-tag-suffix . "-suffix"))))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: accept pre-releases, and custom suffix, prefix, and delimiter" + "2.0.0-alpha" + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "prefix123-2-0-0-alpha-suffix" "Alpha release for 2.0.0")) + (let ((package (make-package directory "1.0.0" + '((accept-pre-releases? . #t) + (release-tag-prefix . "prefix[0-9]{3}-") + (release-tag-suffix . "-suffix") + (release-tag-version-delimiter . "-"))))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: accept pre-releases, no delimiter, and custom suffix, prefix" + "2alpha" + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "prefix123-2alpha-suffix" "Alpha release for version 2")) + (let ((package (make-package directory "1.0.0" + '((accept-pre-releases? . #t) + (release-tag-prefix . "prefix[0-9]{3}-") + (release-tag-suffix . "-suffix") + (release-tag-version-delimiter . ""))))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: no tags found" + #f + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit")) + (let ((package (make-package directory "1.0.0"))) + (latest-git-tag-version package)))) + +(unless (which (git-command)) (test-skip 1)) +(test-equal "latest-git-tag-version: no valid tags found" + #f + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "First commit") + (tag "Test" "Test tag")) + (let ((package (make-package directory "1.0.0"))) + (latest-git-tag-version package)))) + +(test-end "git") diff --git a/tests/import-utils.scm b/tests/import-utils.scm index 874816442e..7c6c782917 100644 --- a/tests/import-utils.scm +++ b/tests/import-utils.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2015, 2017 Ricardo Wurmus <rekado@elephly.net> ;;; Copyright © 2016 Ben Woodcroft <donttrustben@gmail.com> ;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net> +;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev> ;;; ;;; This file is part of GNU Guix. ;;; @@ -64,6 +65,33 @@ '()))) #:guix-name identity)) +(test-equal "recursive-import: skip false packages (toplevel)" + '() + (recursive-import "foo" + #:repo 'repo + #:repo->guix-package + (match-lambda* + (("foo" #:version #f #:repo 'repo) + (values #f '()))) + #:guix-name identity)) + +(test-equal "recursive-import: skip false packages (dependency)" + '((package + (name "foo") + (inputs `(("bar" ,bar))))) + (recursive-import "foo" + #:repo 'repo + #:repo->guix-package + (match-lambda* + (("foo" #:version #f #:repo 'repo) + (values '(package + (name "foo") + (inputs `(("bar" ,bar)))) + '("bar"))) + (("bar" #:version #f #:repo 'repo) + (values #f '()))) + #:guix-name identity)) + (test-assert "alist->package with simple source" (let* ((meta '(("name" . "hello") ("version" . "2.10") diff --git a/tests/inferior.scm b/tests/inferior.scm index 7c3d730d0c..9992077cb2 100644 --- a/tests/inferior.scm +++ b/tests/inferior.scm @@ -26,6 +26,7 @@ #:use-module (gnu packages) #:use-module (gnu packages bootstrap) #:use-module (gnu packages guile) + #:use-module (gnu packages sqlite) #:use-module (srfi srfi-1) #:use-module (srfi srfi-34) #:use-module (srfi srfi-64) @@ -173,9 +174,9 @@ ,(package-version package) ,(package-location package)) ,@rest))))) - (list (map ->list (package-inputs guile-2.2)) - (map ->list (package-native-inputs guile-2.2)) - (map ->list (package-propagated-inputs guile-2.2)))) + (list (map ->list (package-inputs guile-3.0-latest)) + (map ->list (package-native-inputs guile-3.0-latest)) + (map ->list (package-propagated-inputs guile-3.0-latest)))) (let* ((inferior (open-inferior %top-builddir #:command "scripts/guix")) (guile (first (lookup-inferior-packages inferior "guile"))) @@ -260,6 +261,25 @@ (list (inferior-package-derivation %store guile "x86_64-linux") (inferior-package-derivation %store guile "armhf-linux"))))) +(unless (package-replacement sqlite) + (test-skip 1)) + +(test-equal "inferior-package-replacement" + (package-derivation %store + (package-replacement sqlite) + "x86_64-linux") + (let* ((inferior (open-inferior %top-builddir + #:command "scripts/guix")) + (packages (inferior-packages inferior))) + (match (lookup-inferior-packages inferior + (package-name sqlite) + (package-version sqlite)) + ((inferior-sqlite rest ...) + (inferior-package-derivation %store + (inferior-package-replacement + inferior-sqlite) + "x86_64-linux"))))) + (test-equal "inferior-package->manifest-entry" (manifest-entry->list (package->manifest-entry (first (find-best-packages-by-name "guile" #f)))) diff --git a/tests/lint.scm b/tests/lint.scm index bd8604f589..e96265a55a 100644 --- a/tests/lint.scm +++ b/tests/lint.scm @@ -1,13 +1,16 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2012, 2013 Cyril Roelandt <tipecaml@gmail.com> ;;; Copyright © 2014, 2015, 2016 Eric Bavier <bavier@member.fsf.org> -;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2015, 2016 Mathieu Lirzin <mthl@gnu.org> ;;; Copyright © 2016 Hartmut Goebel <h.goebel@crazy-compilers.com> ;;; Copyright © 2017 Alex Kost <alezost@gmail.com> ;;; Copyright © 2017 Efraim Flashner <efraim@flashner.co.il> ;;; Copyright © 2018, 2019 Arun Isaac <arunisaac@systemreboot.net> ;;; Copyright © 2020 Timothy Sample <samplet@ngyro.com> +;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr> +;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz> +;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be> ;;; ;;; This file is part of GNU Guix. ;;; @@ -37,7 +40,7 @@ #:use-module (guix lint) #:use-module (guix ui) #:use-module (guix swh) - #:use-module ((guix gexp) #:select (local-file)) + #:use-module ((guix gexp) #:select (gexp local-file gexp?)) #:use-module ((guix utils) #:select (call-with-temporary-directory)) #:use-module ((guix import hackage) #:select (%hackage-url)) #:use-module ((guix import stackage) #:select (%stackage-url)) @@ -45,6 +48,7 @@ #:use-module (gnu packages glib) #:use-module (gnu packages pkg-config) #:use-module (gnu packages python-xyz) + #:use-module ((gnu packages bash) #:select (bash bash-minimal)) #:use-module (web uri) #:use-module (web server) #:use-module (web server http) @@ -159,6 +163,20 @@ (description "This is a 'quoted' thing.")))) (check-description-style pkg)))) +(test-equal "description: leading whitespace" + "description contains leading whitespace" + (single-lint-warning-message + (let ((pkg (dummy-package "x" + (description " Whitespace.")))) + (check-description-style pkg)))) + +(test-equal "description: trailing whitespace" + "description contains trailing whitespace" + (single-lint-warning-message + (let ((pkg (dummy-package "x" + (description "Whitespace. ")))) + (check-description-style pkg)))) + (test-equal "synopsis: not a string" "invalid synopsis: #f" (single-lint-warning-message @@ -270,6 +288,42 @@ (description "Imagine this is Taylor UUCP.")))) (check-synopsis-style pkg))) +(test-equal "synopsis: contains trailing whitespace" + "synopsis contains trailing whitespace" + (single-lint-warning-message + (let ((pkg (dummy-package "x" + (synopsis "Whitespace ")))) + (check-synopsis-style pkg)))) + +(test-equal "name: use underscore in package name" + "name should use hyphens instead of underscores" + (single-lint-warning-message + (let ((pkg (dummy-package "under_score"))) + (check-name pkg)))) + +(test-equal "tests-true: #:tests? must not be set to #t" + "#:tests? must not be explicitly set to #t" + (single-lint-warning-message + (let ((pkg (dummy-package "x" (arguments '(#:tests? #t))))) + (check-tests-true pkg)))) + +(test-equal "tests-true: absent #:tests? is acceptable" + '() + (let ((pkg (dummy-package "x"))) + (check-tests-true pkg))) + +(test-equal "tests-true: #:tests? #f is acceptable" + '() + (let ((pkg (dummy-package "x" (arguments '(#:tests? #f))))) + (check-tests-true pkg))) + +(test-equal "tests-true: #:tests? #t acceptable when compiling natively" + '() + (let ((pkg (dummy-package "x" + (arguments + `(#:tests? ,(not (%current-target-system))))))) + (check-tests-true pkg))) + (test-equal "inputs: pkg-config is probably a native input" "'pkg-config' should probably be a native input" (single-lint-warning-message @@ -312,6 +366,92 @@ `(("python-setuptools" ,python-setuptools)))))) (check-inputs-should-not-be-an-input-at-all pkg)))) +(test-equal "explicit #:sh argument to 'wrap-program' is acceptable" + '() + (let* ((phases + ;; Loosely based on the "catfish" package + `(modify-phases %standard-phases + (add-after 'install 'wrap + (lambda* (#:key inputs outputs #:allow-other-keys) + (define catfish (string-append (assoc-ref outputs "out") + "/bin/catfish")) + (define hsab (string-append (assoc-ref inputs "hsab") + "/bin/hsab")) + (wrap-program catfish #:sh hsab + `("PYTHONPATH" = (,"blabla"))))))) + (pkg (dummy-package "x" (arguments `(#:phases ,phases))))) + (check-wrapper-inputs pkg))) + +(test-equal + "'check-wrapper-inputs' detects 'wrap-program' without \"bash\" in inputs" + "\"bash-minimal\" should be in 'inputs' when 'wrap-program' is used" + (let* ((phases + `(modify-phases %standard-phases + (add-after 'install 'wrap + (lambda _ + (wrap-program the-binary bla-bla))))) + (pkg (dummy-package "x" (arguments `(#:phases ,phases))))) + (single-lint-warning-message (check-wrapper-inputs pkg)))) + +(test-equal + "'check-wrapper-inputs' detects 'wrap-qt-program' without \"bash\" in inputs" + "\"bash-minimal\" should be in 'inputs' when 'wrap-qt-program' is used" + (let* ((phases + `(modify-phases %standard-phases + (add-after 'install 'qtwrap + (lambda _ + (wrap-qt-program the-binary bla-bla))))) + (pkg (dummy-package "x" (arguments `(#:phases ,phases))))) + (single-lint-warning-message (check-wrapper-inputs pkg)))) + +(test-equal "\"bash\" in 'inputs' satisfies 'check-wrapper-inputs'" + '() + (let* ((phases + `(modify-phases %standard-phases + (add-after 'install 'wrap + (lambda _ + (wrap-program the-binary bla-bla))))) + (pkg (dummy-package "x" (arguments `(#:phases ,phases)) + (inputs `(("bash" ,bash)))))) + (check-wrapper-inputs pkg))) + +(test-equal "\"bash-minimal\" in 'inputs' satisfies 'check-wrapper-inputs'" + '() + (let* ((phases + `(modify-phases %standard-phases + (add-after 'install 'wrap + (lambda _ + (wrap-program THE-BINARY bla-bla))))) + (pkg (dummy-package "x" (arguments `(#:phases ,phases)) + (inputs `(("bash-minimal" ,bash-minimal)))))) + (check-wrapper-inputs pkg))) + +(test-equal "'cut' doesn't hide bad usages of 'wrap-program'" + "\"bash-minimal\" should be in 'inputs' when 'wrap-program' is used" + (let* ((phases + ;; Taken from the "straw-viewer" package + `(modify-phases %standard-phases + (add-after 'install 'wrap-program + (lambda* (#:key outputs #:allow-other-keys) + (let* ((out (assoc-ref outputs "out")) + (bin-dir (string-append out "/bin/")) + (site-dir (string-append out "/lib/perl5/site_perl/")) + (lib-path (getenv "PERL5LIB"))) + (for-each (cut wrap-program <> + `("PERL5LIB" ":" prefix + (,lib-path ,site-dir))) + (find-files bin-dir))))))) + (pkg (dummy-package "x" (arguments `(#:phases ,phases))))) + (single-lint-warning-message (check-wrapper-inputs pkg)))) + +(test-equal "bogus phase specifications don't crash the linter" + "invalid phase clause" + (let* ((phases + `(modify-phases %standard-phases + (add-invalid))) + (pkg (dummy-package "x" (arguments `(#:phases ,phases))))) + (single-lint-warning-message (check-wrapper-inputs pkg)))) + (test-equal "file patches: different file name -> warning" "file names of patches should start with the package name" (single-lint-warning-message @@ -700,6 +840,80 @@ (sha256 %null-sha256)))))) (check-source-unstable-tarball pkg))) +(define (package-with-phase-changes changes) + (dummy-package "x" + (arguments `(#:phases + ,(if (gexp? changes) + #~(modify-phases %standard-phases + #$@changes) + `(modify-phases %standard-phases + ,@changes)))))) + +(test-equal "optional-tests: no check phase" + '() + (let ((pkg (package-with-phase-changes '()))) + (check-optional-tests pkg))) + +(test-equal "optional-tests: check phase respects #:tests?" + '() + (let ((pkg (package-with-phase-changes + '((replace 'check + (lambda* (#:key tests? #:allow-other-keys?) + (when tests? + (invoke "./the-test-suite")))))))) + (check-optional-tests pkg))) + +(test-equal "optional-tests: check phase ignores #:tests?" + "the 'check' phase should respect #:tests?" + (let ((pkg (package-with-phase-changes + '((replace 'check + (lambda _ + (invoke "./the-test-suite"))))))) + (single-lint-warning-message + (check-optional-tests pkg)))) + +(test-equal "optional-tests: do not crash when #:phases is invalid" + "incorrect call to ‘modify-phases’" + (let ((pkg (package-with-phase-changes 'this-is-not-a-list))) + (single-lint-warning-message + (check-optional-tests pkg)))) + +(test-equal "optional-tests: allow G-exps (no warning)" + '() + (let ((pkg (package-with-phase-changes #~()))) + (check-optional-tests pkg))) + +(test-equal "optional-tests: allow G-exps (warning)" + "the 'check' phase should respect #:tests?" + (let ((pkg (package-with-phase-changes + #~((replace 'check + (lambda _ + (invoke "/the-test-suite"))))))) + (single-lint-warning-message + (check-optional-tests pkg)))) + +(test-equal "optional-tests: complicated 'check' phase" + "the 'check' phase should respect #:tests?" + (let ((pkg (package-with-phase-changes + '((replace 'check + (lambda* (#:key inputs tests? #:allow-other-keys) + (let ((something (stuff from inputs or native-inputs))) + (delete-file "dateutil/test/test_utils.py") + (invoke "pytest" "-vv")))))))) + (single-lint-warning-message + (check-optional-tests pkg)))) + +(test-equal "optional-tests: 'check' phase is not first phase" + "the 'check' phase should respect #:tests?" + (let ((pkg (package-with-phase-changes + '((add-after 'unpack + (lambda _ + (chdir "libtestcase-0.0.0"))) + (replace 'check + (lambda _ (invoke "./test-suite"))))))) + (single-lint-warning-message + (check-optional-tests pkg)))) + (test-equal "source: 200" '() (with-http-server `((200 ,%long-string)) @@ -1001,10 +1215,13 @@ (method url-fetch) (uri "http://example.org/foo.tgz") (sha256 (make-bytevector 32)))) - (warnings (with-http-server '((404 "Not archived.")) + (warnings (with-http-server '((404 "Not archived.") + (404 "Not in Disarchive database.")) (parameterize ((%swh-base-url (%local-url))) - (check-archival (dummy-package "x" - (source origin))))))) + (mock ((guix download) %disarchive-mirrors + (list (%local-url))) + (check-archival (dummy-package "x" + (source origin)))))))) (warning-contains? "not archived" warnings))) (test-equal "archival: content available" @@ -1020,6 +1237,29 @@ (parameterize ((%swh-base-url (%local-url))) (check-archival (dummy-package "x" (source origin))))))) +(test-equal "archival: content unavailable but disarchive available" + '() + (let* ((origin (origin + (method url-fetch) + (uri "http://example.org/foo.tgz") + (sha256 (make-bytevector 32)))) + (disarchive (object->string + '(disarchive (version 0) + ... + "swh:1:dir:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))) + ;; https://archive.softwareheritage.org/api/1/directory/ + (directory "[ { \"checksums\": {}, + \"dir_id\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\", + \"type\": \"file\", + \"name\": \"README\" + \"length\": 42 } ]")) + (with-http-server `((404 "") ;lookup-content + (200 ,disarchive) ;Disarchive database lookup + (200 ,directory)) ;lookup-directory + (mock ((guix download) %disarchive-mirrors (list (%local-url))) + (parameterize ((%swh-base-url (%local-url))) + (check-archival (dummy-package "x" (source origin)))))))) + (test-assert "archival: missing revision" (let* ((origin (origin (method git-fetch) @@ -1077,29 +1317,30 @@ (test-assert "haskell-stackage" (let* ((stackage (string-append "{ \"packages\": [{" - " \"name\":\"x\"," + " \"name\":\"pandoc\"," + " \"synopsis\":\"synopsis\"," " \"version\":\"1.0\" }]}")) (packages (map (lambda (version) (dummy-package - (string-append "ghc-x") + "ghc-pandoc" (version version) (source (dummy-origin (method url-fetch) (uri (string-append "https://hackage.haskell.org/package/" - "x-" version "/x-" version ".tar.gz")))))) - '("0.9" "1.0" "2.0"))) + "pandoc-" version "/pandoc-" version ".tar.gz")))))) + '("0.9" "1.0" "100.0"))) (warnings (pk (with-http-server `((200 ,stackage) ; memoized - (200 "name: x\nversion: 1.0\n") - (200 "name: x\nversion: 1.0\n") - (200 "name: x\nversion: 1.0\n")) + (200 "name: pandoc\nversion: 1.0\n") + (200 "name: pandoc\nversion: 1.0\n") + (200 "name: pandoc\nversion: 1.0\n")) (parameterize ((%hackage-url (%local-url)) (%stackage-url (%local-url))) (append-map check-haskell-stackage packages)))))) (match warnings (((? lint-warning? warning)) - (and (string=? (package-version (lint-warning-package warning)) "2.0") + (and (string=? (package-version (lint-warning-package warning)) "100.0") (string-contains (lint-warning-message warning) "ahead of Stackage LTS version")))))) diff --git a/tests/minetest.scm b/tests/minetest.scm new file mode 100644 index 0000000000..abb26d0a03 --- /dev/null +++ b/tests/minetest.scm @@ -0,0 +1,382 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be> +;;; +;;; 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-minetest) + #:use-module (guix memoization) + #:use-module (guix import minetest) + #:use-module (guix import utils) + #:use-module (guix tests) + #:use-module (json) + #:use-module (ice-9 match) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:use-module (srfi srfi-34) + #:use-module (srfi srfi-64)) + + +;; Some procedures for populating a ‘fake’ ContentDB server. + +(define* (make-package-sexp #:key + (guix-name "minetest-foo") + ;; This is not a proper version number but + ;; ContentDB often does not include version + ;; numbers. + (version "2021-07-25") + (home-page "https://example.org/foo") + (repo "https://example.org/foo.git") + (synopsis "synopsis") + (guix-description "description") + (guix-license + '(list license:cc-by-sa4.0 license:lgpl3+)) + (inputs '()) + (upstream-name "Author/foo") + #:allow-other-keys) + `(package + (name ,guix-name) + (version ,version) + (source + (origin + (method git-fetch) + (uri (git-reference + (url ,(and (not (eq? repo 'null)) repo)) + (commit #f))) + (sha256 + (base32 #f)) + (file-name (git-file-name name version)))) + (build-system minetest-mod-build-system) + ,@(maybe-propagated-inputs inputs) + (home-page ,home-page) + (synopsis ,synopsis) + (description ,guix-description) + (license ,guix-license) + (properties + ,(list 'quasiquote + `((upstream-name . ,upstream-name)))))) + +(define* (make-package-json #:key + (author "Author") + (name "foo") + (media-license "CC-BY-SA-4.0") + (license "LGPL-3.0-or-later") + (short-description "synopsis") + (long-description "description") + (repo "https://example.org/foo.git") + (website "https://example.org/foo") + (forums 321) + (score 987.654) + (downloads 123) + (type "mod") + #:allow-other-keys) + `(("author" . ,author) + ("content_warnings" . #()) + ("created_at" . "2018-05-23T19:58:07.422108") + ("downloads" . ,downloads) + ("forums" . ,forums) + ("issue_tracker" . "https://example.org/foo/issues") + ("license" . ,license) + ("long_description" . ,long-description) + ("maintainers" . #("maintainer")) + ("media_license" . ,media-license) + ("name" . ,name) + ("provides" . #("stuff")) + ("release" . 456) + ("repo" . ,repo) + ("score" . ,score) + ("screenshots" . #()) + ("short_description" . ,short-description) + ("state" . "APPROVED") + ("tags" . #("some" "tags")) + ("thumbnail" . null) + ("title" . "The name") + ("type" . ,type) + ("url" . ,(string-append "https://content.minetest.net/packages/" + author "/" name "/download/")) + ("website" . ,website))) + +(define* (make-releases-json #:key (commit #f) (title "2021-07-25") #:allow-other-keys) + `#((("commit" . ,commit) + ("downloads" . 469) + ("id" . 8614) + ("max_minetest_version" . null) + ("min_minetest_version" . null) + ("release_date" . "2021-07-25T01:10:23.207584") + ("title" . ,title)))) + +(define* (make-dependencies-json #:key (author "Author") + (name "foo") + (requirements '(("default" #f ()))) + #:allow-other-keys) + `((,(string-append author "/" name) + . ,(list->vector + (map (match-lambda + ((symbolic-name optional? implementations) + `(("is_optional" . ,optional?) + ("name" . ,symbolic-name) + ("packages" . ,(list->vector implementations))))) + requirements))) + ("something/else" . #()))) + +(define* (make-packages-keys-json #:key (author "Author") + (name "Name") + (type "mod")) + `(("author" . ,author) + ("name" . ,name) + ("type" . ,type))) + +(define (call-with-packages thunk . argument-lists) + ;; Don't reuse results from previous tests. + (invalidate-memoization! contentdb-fetch) + (invalidate-memoization! minetest->guix-package) + (define (scm->json-port scm) + (open-input-string (scm->json-string scm))) + (define (handle-package url requested-author requested-name . rest) + (define relevant-argument-list + (any (lambda (argument-list) + (apply (lambda* (#:key (author "Author") (name "foo") + #:allow-other-keys) + (and (equal? requested-author author) + (equal? requested-name name) + argument-list)) + argument-list)) + argument-lists)) + (when (not relevant-argument-list) + (error "the package ~a/~a should be irrelevant, but ~a is fetched" + requested-author requested-name url)) + (scm->json-port + (apply (match rest + (("") make-package-json) + (("dependencies" "") make-dependencies-json) + (("releases" "") make-releases-json) + (_ (error "TODO ~a" rest))) + relevant-argument-list))) + (define (handle-mod-search sort) + ;; Produce search results, sorted by SORT in descending order. + (define arguments->key + (match sort + ("score" (lambda* (#:key (score 987.654) #:allow-other-keys) + score)) + ("downloads" (lambda* (#:key (downloads 123) #:allow-other-keys) + downloads)))) + (define argument-list->key (cut apply arguments->key <>)) + (define (greater x y) + (> (argument-list->key x) (argument-list->key y))) + (define sorted-argument-lists (sort-list argument-lists greater)) + (define* (arguments->json #:key (author "Author") (name "Foo") (type "mod") + #:allow-other-keys) + (and (string=? type "mod") + `(("author" . ,author) + ("name" . ,name) + ("type" . ,type)))) + (define argument-list->json (cut apply arguments->json <>)) + (scm->json-port + (list->vector (filter-map argument-list->json sorted-argument-lists)))) + (mock ((guix http-client) http-fetch + (lambda* (url #:key headers) + (unless (string-prefix? "mock://api/packages/" url) + (error "the URL ~a should not be used" url)) + (define resource + (substring url (string-length "mock://api/packages/"))) + (define components (string-split resource #\/)) + (match components + ((author name . rest) + (apply handle-package url author name rest)) + (((? (cut string-prefix? "?type=mod&q=" <>) query)) + (handle-mod-search + (cond ((string-contains query "sort=score") "score") + ((string-contains query "sort=downloads") "downloads") + (#t (error "search query ~a has unknown sort key" + query))))) + (_ + (error "the URL ~a should have an author and name component" + url))))) + (parameterize ((%contentdb-api "mock://api/")) + (thunk)))) + +(define* (minetest->guix-package* #:key (author "Author") (name "foo") + (sort %default-sort-key) + #:allow-other-keys) + (minetest->guix-package (string-append author "/" name) #:sort sort)) + +(define (imported-package-sexp* primary-arguments . secondary-arguments) + "Ask the importer to import a package specified by PRIMARY-ARGUMENTS, +during a dynamic where that package and the packages specified by +SECONDARY-ARGUMENTS are available on ContentDB." + (apply call-with-packages + (lambda () + ;; The memoization cache is reset by call-with-packages + (apply minetest->guix-package* primary-arguments)) + primary-arguments + secondary-arguments)) + +(define (imported-package-sexp . extra-arguments) + "Ask the importer to import a package specified by EXTRA-ARGUMENTS, +during a dynamic extent where that package is available on ContentDB." + (imported-package-sexp* extra-arguments)) + +(define-syntax-rule (test-package test-case . extra-arguments) + (test-equal test-case + (make-package-sexp . extra-arguments) + (imported-package-sexp . extra-arguments))) + +(define-syntax-rule (test-package* test-case primary-arguments extra-arguments + ...) + (test-equal test-case + (apply make-package-sexp primary-arguments) + (imported-package-sexp* primary-arguments extra-arguments ...))) + +(test-begin "minetest") + + +;; Package names +(test-package "minetest->guix-package") +(test-package "minetest->guix-package, _ → - in package name" + #:name "foo_bar" + #:guix-name "minetest-foo-bar" + #:upstream-name "Author/foo_bar") + +(test-equal "elaborate names, unambiguous" + "Jeija/mesecons" + (call-with-packages + (cut elaborate-contentdb-name "mesecons") + '(#:name "mesecons" #:author "Jeija") + '(#:name "something" #:author "else"))) + +(test-equal "elaborate name, ambiguous (highest score)" + "Jeija/mesecons" + (call-with-packages + ;; #:sort "score" is the default + (cut elaborate-contentdb-name "mesecons") + '(#:name "mesecons" #:author "Jeijc" #:score 777) + '(#:name "mesecons" #:author "Jeijb" #:score 888) + '(#:name "mesecons" #:author "Jeija" #:score 999))) + + +(test-equal "elaborate name, ambiguous (most downloads)" + "Jeija/mesecons" + (call-with-packages + (cut elaborate-contentdb-name "mesecons" #:sort "downloads") + '(#:name "mesecons" #:author "Jeijc" #:downloads 777) + '(#:name "mesecons" #:author "Jeijb" #:downloads 888) + '(#:name "mesecons" #:author "Jeija" #:downloads 999))) + + +;; Determining the home page +(test-package "minetest->guix-package, website is used as home page" + #:home-page "web://site" + #:website "web://site") +(test-package "minetest->guix-package, if absent, the forum is used" + #:home-page '(minetest-topic 628) + #:forums 628 + #:website 'null) +(test-package "minetest->guix-package, if absent, the git repo is used" + #:home-page "https://github.com/minetest-mods/mesecons" + #:forums 'null + #:website 'null + #:repo "https://github.com/minetest-mods/mesecons") +(test-package "minetest->guix-package, all home page information absent" + #:home-page #f + #:forums 'null + #:website 'null + #:repo 'null) + + +;; Determining the version number + +(test-package "conventional version number" #:version "1.2.3" #:title "1.2.3") +;; See e.g. orwell/basic_trains +(test-package "v-prefixed version number" #:version "1.2.3" #:title "v1.2.3") +;; Many mods on ContentDB use dates as release titles. In that case, the date +;; will have to do. +(test-package "dates as version number" + #:version "2021-01-01" #:title "2021-01-01") + + + +;; Dependencies +(test-package* "minetest->guix-package, unambiguous dependency" + (list #:requirements '(("mesecons" #f + ("Jeija/mesecons" + "some-modpack/containing-mese"))) + #:inputs '("minetest-mesecons")) + (list #:author "Jeija" #:name "mesecons") + (list #:author "some-modpack" #:name "containing-mese" #:type "modpack")) + +(test-package* "minetest->guix-package, ambiguous dependency (highest score)" + (list #:name "frobnicate" + #:guix-name "minetest-frobnicate" + #:upstream-name "Author/frobnicate" + #:requirements '(("frob" #f + ("Author/foo" "Author/bar"))) + ;; #:sort "score" is the default + #:inputs '("minetest-bar")) + (list #:author "Author" #:name "foo" #:score 0) + (list #:author "Author" #:name "bar" #:score 9999)) + +(test-package* "minetest->guix-package, ambiguous dependency (most downloads)" + (list #:name "frobnicate" + #:guix-name "minetest-frobnicate" + #:upstream-name "Author/frobnicate" + #:requirements '(("frob" #f + ("Author/foo" "Author/bar"))) + #:inputs '("minetest-bar") + #:sort "downloads") + (list #:author "Author" #:name "foo" #:downloads 0) + (list #:author "Author" #:name "bar" #:downloads 9999)) + +(test-package "minetest->guix-package, optional dependency" + #:requirements '(("mesecons" #t + ("Jeija/mesecons" + "some-modpack/containing-mese"))) + #:inputs '()) + +;; See e.g. 'orwell/basic_trains' +(test-package* "minetest->guix-package, multiple dependencies implemented by one mod" + (list #:name "frobnicate" + #:guix-name "minetest-frobnicate" + #:upstream-name "Author/frobnicate" + #:requirements '(("frob" #f ("Author/frob")) + ("frob_x" #f ("Author/frob"))) + #:inputs '("minetest-frob")) + (list #:author "Author" #:name "frob")) + + +;; License +(test-package "minetest->guix-package, identical licenses" + #:guix-license 'license:lgpl3+ + #:license "LGPL-3.0-or-later" + #:media-license "LGPL-3.0-or-later") + +;; Sorting +(let* ((make-package + (lambda arguments + (json->package (apply make-package-json arguments)))) + (x (make-package #:score 0)) + (y (make-package #:score 1)) + (z (make-package #:score 2))) + (test-equal "sort-packages, already sorted" + (list z y x) + (sort-packages (list z y x))) + (test-equal "sort-packages, reverse" + (list z y x) + (sort-packages (list x y z)))) + +(test-end "minetest") + +;;; Local Variables: +;;; eval: (put 'test-package* 'scheme-indent-function 1) +;;; End: diff --git a/tests/opam.scm b/tests/opam.scm index 11984b56a6..31b4ea41ff 100644 --- a/tests/opam.scm +++ b/tests/opam.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2018 Julien Lepiller <julien@lepiller.eu> +;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz> ;;; ;;; This file is part of GNU Guix. ;;; @@ -55,6 +56,7 @@ depends: [ synopsis: \"Some example package\" description: \"\"\" This package is just an example.\"\"\" +license: \"BSD-3-Clause\" url { src: \"https://example.org/foo-1.0.0.tar.gz\" checksum: \"md5=74c6e897658e820006106f45f736381f\" @@ -69,26 +71,26 @@ url { (test-begin "opam") (test-assert "opam->guix-package" - (mock ((guix import utils) url-fetch - (lambda (url file-name) - (match url - ("https://example.org/foo-1.0.0.tar.gz" - (begin - (mkdir-p "foo-1.0.0") - (system* "tar" "czvf" file-name "foo-1.0.0/") - (delete-file-recursively "foo-1.0.0") - (set! test-source-hash - (call-with-input-file file-name port-sha256)))) - (_ (error "Unexpected URL: " url))))) - (mock ((guix import opam) get-opam-repository - (const test-repo)) + (mock ((guix import opam) get-opam-repository + (const test-repo)) + (mock ((guix import utils) url-fetch + (lambda (url file-name) + (match url + ("https://example.org/foo-1.0.0.tar.gz" + (begin + (mkdir-p "foo-1.0.0") + (system* "tar" "czvf" file-name "foo-1.0.0/") + (delete-file-recursively "foo-1.0.0") + (set! test-source-hash + (call-with-input-file file-name port-sha256)))) + (_ (error "Unexpected URL: " url))))) (let ((my-package (string-append test-repo "/packages/foo/foo.1.0.0"))) (mkdir-p my-package) (with-output-to-file (string-append my-package "/opam") (lambda _ (format #t "~a" test-opam-file)))) - (match (opam->guix-package "foo" #:repo test-repo) + (match (opam->guix-package "foo" #:repo (list test-repo)) (('package ('name "ocaml-foo") ('version "1.0.0") @@ -109,7 +111,7 @@ url { ('home-page "https://example.org/") ('synopsis "Some example package") ('description "This package is just an example.") - ('license #f)) + ('license 'license:bsd-3)) (string=? (bytevector->nix-base32-string test-source-hash) hash)) diff --git a/tests/pack.scm b/tests/pack.scm index e8455b4f37..e9b4c36e0e 100644 --- a/tests/pack.scm +++ b/tests/pack.scm @@ -1,6 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net> +;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com> ;;; ;;; This file is part of GNU Guix. ;;; @@ -32,6 +33,7 @@ #:use-module ((gnu packages base) #:select (glibc-utf8-locales)) #:use-module (gnu packages bootstrap) #:use-module ((gnu packages compression) #:select (squashfs-tools)) + #:use-module ((gnu packages debian) #:select (dpkg)) #:use-module ((gnu packages guile) #:select (guile-sqlite3)) #:use-module ((gnu packages gnupg) #:select (guile-gcrypt)) #:use-module (srfi srfi-64)) @@ -51,11 +53,13 @@ (define %gzip-compressor ;; Compressor that uses the bootstrap 'gzip'. ((@ (guix scripts pack) compressor) "gzip" - "gz" + ".gz" #~(#+(file-append %bootstrap-coreutils&co "/bin/gzip") "-6n"))) (define %tar-bootstrap %bootstrap-coreutils&co) +(define %ar-bootstrap %bootstrap-binutils) + (test-begin "pack") @@ -270,6 +274,94 @@ 1) (pk 'guilelink (readlink "bin")))) (mkdir #$output)))))))) + (built-derivations (list check)))) + + (unless store (test-skip 1)) + (test-assertm "deb archive with symlinks and control files" store + (mlet* %store-monad + ((guile (set-guile-for-build (default-guile))) + (profile (profile-derivation (packages->manifest + (list %bootstrap-guile)) + #:hooks '() + #:locales? #f)) + (deb (debian-archive + "deb-pack" profile + #:compressor %gzip-compressor + #:symlinks '(("/opt/gnu/bin" -> "bin")) + #:archiver %tar-bootstrap + #:extra-options + (list #:triggers-file + (plain-file "triggers" + "activate-noawait /usr/share/icons/hicolor\n") + #:postinst-file + (plain-file "postinst" + "echo running configure script\n")))) + (check + (gexp->derivation "check-deb-pack" + (with-imported-modules '((guix build utils)) + #~(begin + (use-modules (guix build utils) + (ice-9 match) + (ice-9 popen) + (ice-9 rdelim) + (ice-9 textual-ports) + (rnrs base)) + + (setenv "PATH" (string-join + (list (string-append #+%tar-bootstrap "/bin") + (string-append #+dpkg "/bin") + (string-append #+%ar-bootstrap "/bin")) + ":")) + + ;; Validate the output of 'dpkg --info'. + (let* ((port (open-pipe* OPEN_READ "dpkg" "--info" #$deb)) + (info (get-string-all port)) + (exit-val (status:exit-val (close-pipe port)))) + (assert (zero? exit-val)) + + (assert (string-contains + info + (string-append "Package: " + #+(package-name %bootstrap-guile)))) + + (assert (string-contains + info + (string-append "Version: " + #+(package-version %bootstrap-guile))))) + + ;; Sanity check .deb contents. + (invoke "ar" "-xv" #$deb) + (assert (file-exists? "debian-binary")) + (assert (file-exists? "data.tar.gz")) + (assert (file-exists? "control.tar.gz")) + + ;; Verify there are no hard links in data.tar.gz, as hard + ;; links would cause dpkg to fail unpacking the archive. + (define hard-links + (let ((port (open-pipe* OPEN_READ "tar" "-tvf" "data.tar.gz"))) + (let loop ((hard-links '())) + (match (read-line port) + ((? eof-object?) + (assert (zero? (status:exit-val (close-pipe port)))) + hard-links) + (line + (if (string-prefix? "u" line) + (loop (cons line hard-links)) + (loop hard-links))))))) + + (unless (null? hard-links) + (error "hard links found in data.tar.gz" hard-links)) + + ;; Verify the presence of the control files. + (invoke "tar" "-xf" "control.tar.gz") + (assert (file-exists? "control")) + (assert (and (file-exists? "postinst") + (= #o111 ;script is executable + (logand #o111 (stat:perms + (stat "postinst")))))) + (assert (file-exists? "triggers")) + + (mkdir #$output)))))) (built-derivations (list check))))) (test-end) diff --git a/tests/packages.scm b/tests/packages.scm index 2a290bc353..3756877270 100644 --- a/tests/packages.scm +++ b/tests/packages.scm @@ -236,6 +236,17 @@ (eq? item new))) (null? (manifest-transaction-remove tx))))))) +(test-assert "package-definition-location" + (let ((location (package-location hello)) + (definition (package-definition-location hello))) + ;; Check for the usual layout of (define-public hello (package ...)). + (and (string=? (location-file location) + (location-file definition)) + (= 0 (location-column definition)) + (= 2 (location-column location)) + (= (location-line definition) + (- (location-line location) 1))))) + (test-assert "package-field-location" (let () (define (goto port line column) diff --git a/tests/profiles.scm b/tests/profiles.scm index ce77711d63..06a0387221 100644 --- a/tests/profiles.scm +++ b/tests/profiles.scm @@ -279,6 +279,63 @@ (string=? (dirname (readlink bindir)) (derivation->output-path guile)))))) +(test-assertm "profile-derivation, ordering & collisions" + ;; ENTRY1 and ENTRY2 both provide 'bin/guile'--a collision. Make sure + ;; ENTRY1 "wins" over ENTRY2. See <https://bugs.gnu.org/49102>. + (mlet* %store-monad + ((entry1 -> (package->manifest-entry %bootstrap-guile)) + (entry2 -> (manifest-entry + (name "fake-guile") + (version "0") + (item (computed-file + "fake-guile" + #~(begin + (mkdir #$output) + (mkdir (string-append #$output "/bin")) + (call-with-output-file + (string-append #$output "/bin/guile") + (lambda (port) + (display "Fake!\n" port)))))))) + (guile (package->derivation %bootstrap-guile)) + (drv (profile-derivation (manifest (list entry1 entry2)) + #:hooks '() + #:locales? #f)) + (profile -> (derivation->output-path drv)) + (bindir -> (string-append profile "/bin")) + (file -> (string-append bindir "/guile")) + (_ (built-derivations (list drv)))) + (return (string=? (readlink file) + (string-append + (derivation->output-path guile) + "/bin/guile"))))) + +(test-assertm "load-profile" + (mlet* %store-monad + ((entry -> (package->manifest-entry %bootstrap-guile)) + (guile (package->derivation %bootstrap-guile)) + (drv (profile-derivation (manifest (list entry)) + #:hooks '() + #:locales? #f)) + (profile -> (derivation->output-path drv)) + (bindir -> (string-append profile "/bin")) + (_ (built-derivations (list drv)))) + (define-syntax-rule (with-environment-excursion exp ...) + (let ((env (environ))) + (dynamic-wind + (const #t) + (lambda () exp ...) + (lambda () (environ env))))) + + (return (and (with-environment-excursion + (load-profile profile) + (and (string-prefix? (string-append bindir ":") + (getenv "PATH")) + (getenv "GUILE_LOAD_PATH"))) + (with-environment-excursion + (load-profile profile #:pure? #t #:white-list '()) + (equal? (list (string-append "PATH=" bindir)) + (environ))))))) + (test-assertm "<profile>" (mlet* %store-monad ((entry -> (package->manifest-entry %bootstrap-guile)) diff --git a/tests/publish.scm b/tests/publish.scm index 3e67c435ac..c3d086995a 100644 --- a/tests/publish.scm +++ b/tests/publish.scm @@ -1,7 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2015 David Thompson <davet@gnu.org> ;;; Copyright © 2020 by Amar M. Singh <nly@disroot.org> -;;; Copyright © 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -700,6 +700,36 @@ References: ~%" (= (response-content-length response) (stat:size (stat log))) (first (response-content-type response)))))) +(test-equal "negative TTL" + `(404 42) + + (call-with-temporary-directory + (lambda (cache) + (let ((thread (with-separate-output-ports + (call-with-new-thread + (lambda () + (guix-publish "--port=6786" "-C0" + "--negative-ttl=42s")))))) + (wait-until-ready 6786) + + (let* ((base "http://localhost:6786/") + (url (string-append base (make-string 32 #\z) + ".narinfo")) + (response (http-get url))) + (list (response-code response) + (match (assq-ref (response-headers response) 'cache-control) + ((('max-age . ttl)) ttl) + (_ #f)))))))) + +(test-equal "no negative TTL" + `(404 #f) + (let* ((uri (publish-uri + (string-append "/" (make-string 32 #\z) + ".narinfo"))) + (response (http-get uri))) + (list (response-code response) + (assq-ref (response-headers response) 'cache-control)))) + (test-equal "/log/NAME not found" 404 (let ((uri (publish-uri "/log/does-not-exist"))) diff --git a/tests/pypi.scm b/tests/pypi.scm index f421d6d9df..70f4298a90 100644 --- a/tests/pypi.scm +++ b/tests/pypi.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2014 David Thompson <davet@gnu.org> ;;; Copyright © 2016 Ricardo Wurmus <rekado@elephly.net> ;;; Copyright © 2019 Maxim Cournoyer <maxim.cournoyer@gmail.com> +;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz> ;;; ;;; This file is part of GNU Guix. ;;; @@ -29,7 +30,7 @@ #:use-module (srfi srfi-64) #:use-module (ice-9 match)) -(define test-json +(define test-json-1 "{ \"info\": { \"version\": \"1.0.0\", @@ -57,6 +58,34 @@ } }") +(define test-json-2 + "{ + \"info\": { + \"version\": \"1.0.0\", + \"name\": \"foo-99\", + \"license\": \"GNU LGPL\", + \"summary\": \"summary\", + \"home_page\": \"http://example.com\", + \"classifiers\": [], + \"download_url\": \"\" + }, + \"urls\": [], + \"releases\": { + \"1.0.0\": [ + { + \"url\": \"https://example.com/foo-99-1.0.0.egg\", + \"packagetype\": \"bdist_egg\" + }, { + \"url\": \"https://example.com/foo-99-1.0.0.tar.gz\", + \"packagetype\": \"sdist\" + }, { + \"url\": \"https://example.com/foo-99-1.0.0-py2.py3-none-any.whl\", + \"packagetype\": \"bdist_wheel\" + } + ] + } +}") + (define test-source-hash "") @@ -147,6 +176,13 @@ Requires-Dist: pytest (>=3.1.0); extra == 'testing' (uri (list "https://bitheap.org/cram/cram-0.7.tar.gz" (pypi-uri "cram" "0.7")))))))) +(test-equal "guix-package->pypi-name, honor 'upstream-name'" + "bar-3" + (guix-package->pypi-name + (dummy-package "foo" + (properties + '((upstream-name . "bar-3")))))) + (test-equal "specification->requirement-name" '("Fizzy" "PickyThing" "SomethingWithMarker" "requests" "pip") (map specification->requirement-name test-specifications)) @@ -198,8 +234,8 @@ Requires-Dist: pytest (>=3.1.0); extra == 'testing' (lambda (url . rest) (match url ("https://pypi.org/pypi/foo/json" - (values (open-input-string test-json) - (string-length test-json))) + (values (open-input-string test-json-1) + (string-length test-json-1))) ("https://example.com/foo-1.0.0-py2.py3-none-any.whl" #f) (_ (error "Unexpected URL: " url))))) (match (pypi->guix-package "foo") @@ -264,8 +300,8 @@ Requires-Dist: pytest (>=3.1.0); extra == 'testing' (lambda (url . rest) (match url ("https://pypi.org/pypi/foo/json" - (values (open-input-string test-json) - (string-length test-json))) + (values (open-input-string test-json-1) + (string-length test-json-1))) ("https://example.com/foo-1.0.0-py2.py3-none-any.whl" #f) (_ (error "Unexpected URL: " url))))) ;; Not clearing the memoization cache here would mean returning the value @@ -317,8 +353,8 @@ Requires-Dist: pytest (>=3.1.0); extra == 'testing' (lambda (url . rest) (match url ("https://pypi.org/pypi/foo/json" - (values (open-input-string test-json) - (string-length test-json))) + (values (open-input-string test-json-1) + (string-length test-json-1))) ("https://example.com/foo-1.0.0-py2.py3-none-any.whl" #f) (_ (error "Unexpected URL: " url))))) ;; Not clearing the memoization cache here would mean returning the value @@ -345,4 +381,60 @@ Requires-Dist: pytest (>=3.1.0); extra == 'testing' (x (pk 'fail x #f)))))) +(test-assert "pypi->guix-package, package name contains \"-\" followed by digits" + ;; Replace network resources with sample data. + (mock ((guix import utils) url-fetch + (lambda (url file-name) + (match url + ("https://example.com/foo-99-1.0.0.tar.gz" + (begin + ;; Unusual requires.txt location should still be found. + (mkdir-p "foo-99-1.0.0/src/bizarre.egg-info") + (with-output-to-file "foo-99-1.0.0/src/bizarre.egg-info/requires.txt" + (lambda () + (display test-requires.txt))) + (parameterize ((current-output-port (%make-void-port "rw+"))) + (system* "tar" "czvf" file-name "foo-99-1.0.0/")) + (delete-file-recursively "foo-99-1.0.0") + (set! test-source-hash + (call-with-input-file file-name port-sha256)))) + ("https://example.com/foo-99-1.0.0-py2.py3-none-any.whl" #f) + (_ (error "Unexpected URL: " url))))) + (mock ((guix http-client) http-fetch + (lambda (url . rest) + (match url + ("https://pypi.org/pypi/foo-99/json" + (values (open-input-string test-json-2) + (string-length test-json-2))) + ("https://example.com/foo-99-1.0.0-py2.py3-none-any.whl" #f) + (_ (error "Unexpected URL: " url))))) + (match (pypi->guix-package "foo-99") + (('package + ('name "python-foo-99") + ('version "1.0.0") + ('source ('origin + ('method 'url-fetch) + ('uri ('pypi-uri "foo-99" 'version)) + ('sha256 + ('base32 + (? string? hash))))) + ('properties ('quote (("upstream-name" . "foo-99")))) + ('build-system 'python-build-system) + ('propagated-inputs + ('quasiquote + (("python-bar" ('unquote 'python-bar)) + ("python-foo" ('unquote 'python-foo))))) + ('native-inputs + ('quasiquote + (("python-pytest" ('unquote 'python-pytest))))) + ('home-page "http://example.com") + ('synopsis "summary") + ('description "summary") + ('license 'license:lgpl2.0)) + (string=? (bytevector->nix-base32-string + test-source-hash) + hash)) + (x + (pk 'fail x #f)))))) + (test-end "pypi") diff --git a/tests/records.scm b/tests/records.scm index 2c55a61720..d014e7a995 100644 --- a/tests/records.scm +++ b/tests/records.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -29,6 +29,16 @@ (module-use! module (resolve-interface '(guix records))) module)) +(define (location-alist loc) + ;; Return a location alist. In Guile < 3.0.6, LOC is always an alist, but + ;; starting with 3.0.6, LOC is a vector (at least when it comes from + ;; 'syntax-error' exceptions), hence this conversion. + (match loc + (#(file line column) + `((line . ,line) (column . ,column) + (filename . ,file))) + (_ loc))) + (test-begin "records") @@ -273,6 +283,44 @@ (equal? (foo-bar y) 1)) ;promise was already forced (eq? (foo-baz y) 'b))))) +(test-assert "define-record-type* & sanitize" + (begin + (define-record-type* <foo> foo make-foo + foo? + (bar foo-bar + (default "bar") + (sanitize (lambda (x) (string-append x "!"))))) + + (let* ((p (foo)) + (q (foo (inherit p))) + (r (foo (inherit p) (bar "baz"))) + (s (foo (bar "baz")))) + (and (string=? (foo-bar p) "bar!") + (equal? q p) + (string=? (foo-bar r) "baz!") + (equal? s r))))) + +(test-assert "define-record-type* & sanitize & thunked" + (let ((sanitized 0)) + (define-record-type* <foo> foo make-foo + foo? + (bar foo-bar + (default "bar") + (sanitize (lambda (x) + (set! sanitized (+ 1 sanitized)) + (string-append x "!"))))) + + (let ((p (foo))) + (and (string=? (foo-bar p) "bar!") + (string=? (foo-bar p) "bar!") ;twice + (= sanitized 1) ;sanitizer was called at init time only + (let ((q (foo (bar "baz")))) + (and (string=? (foo-bar q) "baz!") + (string=? (foo-bar q) "baz!") ;twice + (= sanitized 2) + (let ((r (foo (inherit q)))) + (and (string=? (foo-bar r) "baz!") + (= sanitized 2))))))))) ;no re-sanitization (test-assert "define-record-type* & wrong field specifier" (let ((exp '(begin (define-record-type* <foo> foo make-foo @@ -298,7 +346,7 @@ (pk 'expected-loc `((line . ,(- (assq-ref loc 'line) 1)) ,@(alist-delete 'line loc))) - (pk 'actual-loc location))))))) + (pk 'actual-loc (location-alist location)))))))) (test-assert "define-record-type* & wrong field specifier, identifier" (let ((exp '(begin @@ -325,7 +373,7 @@ (pk 'expected-loc `((line . ,(- (assq-ref loc 'line) 2)) ,@(alist-delete 'line loc))) - (pk 'actual-loc location))))))) + (pk 'actual-loc (location-alist location)))))))) (test-assert "define-record-type* & missing initializers" (catch 'syntax-error @@ -396,7 +444,7 @@ (pk 'expected-loc `((line . ,(- (assq-ref loc 'line) 1)) ,@(alist-delete 'line loc))) - (pk 'actual-loc location))))))) + (pk 'actual-loc (location-alist location)))))))) (test-assert "ABI checks" (let ((module (test-module))) diff --git a/tests/services/configuration.scm b/tests/services/configuration.scm new file mode 100644 index 0000000000..86a36a388d --- /dev/null +++ b/tests/services/configuration.scm @@ -0,0 +1,120 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com> +;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz> +;;; +;;; 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 (tests services configuration) + #:use-module (gnu services configuration) + #:use-module (guix gexp) + #:use-module (srfi srfi-34) + #:use-module (srfi srfi-64)) + +;;; Tests for the (gnu services configuration) module. + +(test-begin "services-configuration") + + +;;; +;;; define-configuration macro. +;;; + +(define-configuration port-configuration + (port (number 80) "The port number.") + (no-serialization)) + +(test-equal "default value, no serialization" + 80 + (port-configuration-port (port-configuration))) + +(define-configuration port-configuration-cs + (port (number 80) "The port number." empty-serializer)) + +(test-equal "default value, custom serializer" + 80 + (port-configuration-cs-port (port-configuration-cs))) + +(define serialize-number "") +(define-configuration port-configuration-ndv + (port (number) "The port number.")) + +(test-equal "no default value, provided" + 55 + (port-configuration-ndv-port (port-configuration-ndv + (port 55)))) + +(test-assert "no default value, not provided" + (guard (c ((configuration-error? c) + #t)) + (port-configuration-ndv-port (port-configuration-ndv)))) + +(define (custom-number-serializer name value) + (format #f "~a = ~a;" name value)) + +(define-configuration serializable-configuration + (port (number 80) "The port number." custom-number-serializer)) + +(test-assert "serialize-configuration" + (gexp? + (let ((config (serializable-configuration))) + (serialize-configuration config serializable-configuration-fields)))) + +(define-configuration serializable-configuration + (port (number 80) "The port number." custom-number-serializer) + (no-serialization)) + +(test-assert "serialize-configuration with no-serialization" + ;; When serialization is disabled, the serializer is set to #f, so + ;; attempting to use it fails with a 'wrong-type-arg' error. + (not (false-if-exception + (let ((config (serializable-configuration))) + (serialize-configuration config serializable-configuration-fields))))) + +(define (custom-prefix-serialize-integer field-name name) name) + +(define-configuration configuration-with-prefix + (port (integer 10) "The port number.") + (prefix custom-prefix-)) + +(test-assert "serialize-configuration with prefix" + (gexp? + (let ((config (configuration-with-prefix))) + (serialize-configuration config configuration-with-prefix-fields)))) + + +;;; +;;; define-maybe macro. +;;; +(define-maybe number) + +(define-configuration config-with-maybe-number + (port (maybe-number 80) "The port number.")) + +(define (serialize-number field value) + (format #f "~a=~a" field value)) + +(test-equal "maybe value serialization" + "port=80" + (serialize-maybe-number "port" 80)) + +(define-maybe/no-serialization string) + +(define-configuration config-with-maybe-string/no-serialization + (name (maybe-string) "The name of the item.") + (no-serialization)) + +(test-assert "maybe value without serialization no procedure bound" + (not (defined? 'serialize-maybe-string))) diff --git a/tests/services/telephony.scm b/tests/services/telephony.scm new file mode 100644 index 0000000000..b4a0f120d4 --- /dev/null +++ b/tests/services/telephony.scm @@ -0,0 +1,446 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com> +;;; +;;; 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 (tests services telephony) + #:use-module (gnu build jami-service) + #:use-module (gnu services telephony) + #:use-module (srfi srfi-64)) + +;;; Tests for the (gnu services telephony) and related modules. + +(test-begin "jami-service") + +(define parse-dbus-reply + (@@ (gnu build jami-service) parse-dbus-reply)) + +(define parse-account-ids + (@@ (gnu build jami-service) parse-account-ids)) + +(define parse-account-details + (@@ (gnu build jami-service) parse-account-details)) + +(define parse-contacts + (@@ (gnu build jami-service) parse-contacts)) + +(define jami-account->alist + (@@ (gnu services telephony) jami-account->alist)) + +;; $ dbus-send --print-reply --dest="cx.ring.Ring" \ +;; "/cx/ring/Ring/ConfigurationManager" \ +;; "cx.ring.Ring.ConfigurationManager.getAccountList" +(define getAccountList-reply "\ +method return time=1622217253.386711 sender=:1.7 -> destination=:1.14 serial=140 reply_serial=2 + array [ + string \"addf37fbb558d6a0\" + string \"d5cbeb7d08c98a65\" + string \"398af0c6b74ce101\" + ] +") + +(test-equal "parse-account-ids" + '("addf37fbb558d6a0" "d5cbeb7d08c98a65" "398af0c6b74ce101") + (parse-account-ids getAccountList-reply)) + +;; $ dbus-send --print-reply --dest="cx.ring.Ring" \ +;; "/cx/ring/Ring/ConfigurationManager" \ +;; "cx.ring.Ring.ConfigurationManager.getAccountDetails" \ +;; 'string:398af0c6b74ce101' +(define getAccountDetails-reply "\ +method return time=1622254991.789588 sender=:1.7 -> destination=:1.19 serial=145 reply_serial=2 + array [ + dict entry( + string \"Account.accountDiscovery\" + string \"false\" + ) + dict entry( + string \"Account.accountPublish\" + string \"false\" + ) + dict entry( + string \"Account.activeCallLimit\" + string \"-1\" + ) + dict entry( + string \"Account.alias\" + string \"some-rendezvous-point-name\" + ) + dict entry( + string \"Account.allModeratorEnabled\" + string \"true\" + ) + dict entry( + string \"Account.allowCertFromContact\" + string \"true\" + ) + dict entry( + string \"Account.allowCertFromHistory\" + string \"true\" + ) + dict entry( + string \"Account.allowCertFromTrusted\" + string \"true\" + ) + dict entry( + string \"Account.archiveHasPassword\" + string \"false\" + ) + dict entry( + string \"Account.audioPortMax\" + string \"32766\" + ) + dict entry( + string \"Account.audioPortMin\" + string \"16384\" + ) + dict entry( + string \"Account.autoAnswer\" + string \"false\" + ) + dict entry( + string \"Account.defaultModerators\" + string \"\" + ) + dict entry( + string \"Account.deviceID\" + string \"94b4070fc7a8afa8482c777a9822c52e6af2e1bd\" + ) + dict entry( + string \"Account.deviceName\" + string \"some-device\" + ) + dict entry( + string \"Account.dhtProxyListUrl\" + string \"https://config.jami.net/proxyList\" + ) + dict entry( + string \"Account.displayName\" + string \"some-rendezvous-point-name\" + ) + dict entry( + string \"Account.dtmfType\" + string \"overrtp\" + ) + dict entry( + string \"Account.enable\" + string \"true\" + ) + dict entry( + string \"Account.hasCustomUserAgent\" + string \"false\" + ) + dict entry( + string \"Account.hostname\" + string \"bootstrap.jami.net\" + ) + dict entry( + string \"Account.localInterface\" + string \"default\" + ) + dict entry( + string \"Account.localModeratorsEnabled\" + string \"true\" + ) + dict entry( + string \"Account.mailbox\" + string \"\" + ) + dict entry( + string \"Account.managerUri\" + string \"\" + ) + dict entry( + string \"Account.managerUsername\" + string \"\" + ) + dict entry( + string \"Account.peerDiscovery\" + string \"false\" + ) + dict entry( + string \"Account.presenceSubscribeSupported\" + string \"true\" + ) + dict entry( + string \"Account.proxyEnabled\" + string \"false\" + ) + dict entry( + string \"Account.proxyPushToken\" + string \"\" + ) + dict entry( + string \"Account.proxyServer\" + string \"dhtproxy.jami.net:[80-95]\" + ) + dict entry( + string \"Account.publishedAddress\" + string \"\" + ) + dict entry( + string \"Account.publishedPort\" + string \"5060\" + ) + dict entry( + string \"Account.publishedSameAsLocal\" + string \"true\" + ) + dict entry( + string \"Account.rendezVous\" + string \"true\" + ) + dict entry( + string \"Account.ringtoneEnabled\" + string \"true\" + ) + dict entry( + string \"Account.ringtonePath\" + string \"/usr/share/ring/ringtones/default.opus\" + ) + dict entry( + string \"Account.type\" + string \"RING\" + ) + dict entry( + string \"Account.upnpEnabled\" + string \"true\" + ) + dict entry( + string \"Account.useragent\" + string \"\" + ) + dict entry( + string \"Account.username\" + string \"ccb8bbe2382343f7feb140710ab48aaf1b55634e\" + ) + dict entry( + string \"Account.videoEnabled\" + string \"true\" + ) + dict entry( + string \"Account.videoPortMax\" + string \"65534\" + ) + dict entry( + string \"Account.videoPortMin\" + string \"49152\" + ) + dict entry( + string \"DHT.PublicInCalls\" + string \"true\" + ) + dict entry( + string \"DHT.port\" + string \"7766\" + ) + dict entry( + string \"RingNS.account\" + string \"3989b55313a911b6f0c004748b49b254f35c9ef6\" + ) + dict entry( + string \"RingNS.uri\" + string \"\" + ) + dict entry( + string \"SRTP.enable\" + string \"true\" + ) + dict entry( + string \"SRTP.keyExchange\" + string \"sdes\" + ) + dict entry( + string \"SRTP.rtpFallback\" + string \"false\" + ) + dict entry( + string \"STUN.enable\" + string \"false\" + ) + dict entry( + string \"STUN.server\" + string \"\" + ) + dict entry( + string \"TLS.certificateFile\" + string \"/var/lib/jami/.local/share/jami/398af0c6b74ce101/ring_device.crt\" + ) + dict entry( + string \"TLS.certificateListFile\" + string \"\" + ) + dict entry( + string \"TLS.ciphers\" + string \"\" + ) + dict entry( + string \"TLS.method\" + string \"Automatic\" + ) + dict entry( + string \"TLS.negotiationTimeoutSec\" + string \"-1\" + ) + dict entry( + string \"TLS.password\" + string \"\" + ) + dict entry( + string \"TLS.privateKeyFile\" + string \"/var/lib/jami/.local/share/jami/398af0c6b74ce101/ring_device.key\" + ) + dict entry( + string \"TLS.requireClientCertificate\" + string \"true\" + ) + dict entry( + string \"TLS.serverName\" + string \"\" + ) + dict entry( + string \"TLS.verifyClient\" + string \"true\" + ) + dict entry( + string \"TLS.verifyServer\" + string \"true\" + ) + dict entry( + string \"TURN.enable\" + string \"true\" + ) + dict entry( + string \"TURN.password\" + string \"ring\" + ) + dict entry( + string \"TURN.realm\" + string \"ring\" + ) + dict entry( + string \"TURN.server\" + string \"turn.jami.net\" + ) + dict entry( + string \"TURN.username\" + string \"ring\" + ) + ] +") + +(test-equal "parse-account-details; username, alias and display name" + '("ccb8bbe2382343f7feb140710ab48aaf1b55634e" ;username + "some-rendezvous-point-name" ;alias + "some-rendezvous-point-name") ;displayName + (let ((account-details (parse-account-details getAccountDetails-reply))) + (list (assoc-ref account-details "Account.username") + (assoc-ref account-details "Account.alias") + (assoc-ref account-details "Account.displayName")))) + +(define getContacts-reply "\ +method return time=1627014042.752673 sender=:1.113 -> destination=:1.186 serial=220 reply_serial=2 + array [ + array [ + dict entry( + string \"added\" + string \"1578883327\" + ) + dict entry( + string \"confirmed\" + string \"true\" + ) + dict entry( + string \"id\" + string \"1c7d5a09464223442549fef172a3cf6f4de9b01c\" + ) + ] + array [ + dict entry( + string \"added\" + string \"1623107941\" + ) + dict entry( + string \"confirmed\" + string \"true\" + ) + dict entry( + string \"id\" + string \"5903c6c9ac5cb863c64e559add3d5d1c8c563449\" + ) + ] + array [ + dict entry( + string \"added\" + string \"1595996256\" + ) + dict entry( + string \"confirmed\" + string \"true\" + ) + dict entry( + string \"id\" + string \"ff2d72a548693214fb3a0f0f7a943b5e2bb9be03\" + ) + ] + ]") + +(test-equal "parse-account-contacts" + '((("added" . "1578883327") + ("confirmed" . "true") + ("id" . "1c7d5a09464223442549fef172a3cf6f4de9b01c")) + (("added" . "1623107941") + ("confirmed" . "true") + ("id" . "5903c6c9ac5cb863c64e559add3d5d1c8c563449")) + (("added" . "1595996256") + ("confirmed" . "true") + ("id" . "ff2d72a548693214fb3a0f0f7a943b5e2bb9be03"))) + (parse-contacts getContacts-reply)) + +(define getContacts-empty-reply "\ +method return time=1627400787.873988 sender=:1.1197 -> destination=:1.1463 serial=2127 reply_serial=2 + array [ + ]") + +(test-equal "parse-account-contacts, empty array" + '() + (parse-contacts getContacts-empty-reply)) + +(define %dummy-jami-account (jami-account + (archive "/tmp/dummy.gz"))) + +(define %dummy-jami-account-2 (jami-account + (archive "/tmp/dummy.gz") + (rendezvous-point? #t) + (peer-discovery? #f) + (bootstrap-hostnames '("bootstrap.me" + "fallback.another.host")) + (name-server-uri "https://my.name.server"))) + +(test-equal "jami-account->alist, no account detail value set" + '() + (jami-account->alist %dummy-jami-account)) + +(test-equal "jami-account->alist, with account detail values" + '(("Account.hostname" . "bootstrap.me;fallback.another.host") + ("Account.peerDiscovery" . "false") + ("Account.rendezVous" . "true") + ("RingNS.uri" . "https://my.name.server")) + (sort (jami-account->alist %dummy-jami-account-2) + (lambda (x y) + (string<=? (car x) (car y))))) + +(test-end) diff --git a/tests/snix.scm b/tests/snix.scm deleted file mode 100644 index 4c31e3389d..0000000000 --- a/tests/snix.scm +++ /dev/null @@ -1,73 +0,0 @@ -;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2012, 2013, 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-snix) - #:use-module (guix import snix) - #:use-module (srfi srfi-1) - #:use-module (srfi srfi-64) - #:use-module (ice-9 match)) - -(define %nixpkgs-directory - (getenv "NIXPKGS")) - -(define factorize-uri - (@@ (guix import snix) factorize-uri)) - -(define-syntax-rule (every? proc lists ...) - (not (not (every proc lists ...)))) - -(test-begin "snix") - -(test-assert "factorize-uri" - (every? (match-lambda - ((uri version '-> expected) - (equal? (factorize-uri uri version) - expected))) - '(("http://example.com/foo.tgz" "1.0" - -> "http://example.com/foo.tgz") - ("http://example.com/foo-2.8.tgz" "2.8" - -> ("http://example.com/foo-" version ".tgz")) - ("http://example.com/2.8/foo-2.8.tgz" "2.8" - -> ("http://example.com/" version "/foo-" version ".tgz"))))) - -(test-skip (if (and %nixpkgs-directory - (file-exists? (string-append %nixpkgs-directory - "/default.nix"))) - 0 - 1)) - -(test-assert "nixpkgs->guix-package" - (match (nixpkgs->guix-package %nixpkgs-directory "guile") - (('package - ('name "guile") - ('version (? string?)) - ('source ('origin _ ...)) - ('build-system _) - ('inputs ('quasiquote (inputs ...))) - ('propagated-inputs ('quasiquote (pinputs ...))) - ('home-page (? string?)) - ('synopsis (? string?)) - ('description (? string?)) - ('license (? symbol?))) - (and (member '("libffi" ,libffi) inputs) - (member '("gmp" ,gmp) pinputs) - #t)) - (x - (pk 'fail x #f)))) - -(test-end "snix") diff --git a/tests/store.scm b/tests/store.scm index 9c25adf5e9..95f47c3af3 100644 --- a/tests/store.scm +++ b/tests/store.scm @@ -308,42 +308,6 @@ (null? (references %store t1)) (null? (referrers %store t2))))) -(test-assert "references/substitutes missing reference info" - (with-store s - (set-build-options s #:use-substitutes? #f) - (guard (c ((store-protocol-error? c) #t)) - (let* ((b (add-to-store s "bash" #t "sha256" - (search-bootstrap-binary "bash" - (%current-system)))) - (d (derivation s "the-thing" b '("--help") - #:inputs `((,b))))) - (references/substitutes s (list (derivation->output-path d) b)) - #f)))) - -(test-assert "references/substitutes with substitute info" - (with-store s - (set-build-options s #:use-substitutes? #t) - (let* ((t1 (add-text-to-store s "random1" (random-text))) - (t2 (add-text-to-store s "random2" (random-text) - (list t1))) - (t3 (add-text-to-store s "build" "echo -n $t2 > $out")) - (b (add-to-store s "bash" #t "sha256" - (search-bootstrap-binary "bash" - (%current-system)))) - (d (derivation s "the-thing" b `("-e" ,t3) - #:inputs `((,b) (,t3) (,t2)) - #:env-vars `(("t2" . ,t2)))) - (o (derivation->output-path d))) - (with-derivation-narinfo d - (sha256 => (gcrypt:sha256 (string->utf8 t2))) - (references => (list t2)) - - (equal? (references/substitutes s (list o t3 t2 t1)) - `((,t2) ;refs of O - () ;refs of T3 - (,t1) ;refs of T2 - ())))))) ;refs of T1 - (test-equal "substitutable-path-info when substitutes are turned off" '() (with-store s @@ -490,6 +454,42 @@ (derivation->output-path drv))) (list d1 d2))))) +(test-equal "map/accumulate-builds cutoff" ;https://issues.guix.gnu.org/50264 + (iota 20) + + ;; Make sure that, when the cutoff is reached, 'map/accumulate-builds' still + ;; returns the right result and calls the build handler by batches. + (let* ((b (add-text-to-store %store "build" "echo $foo > $out" '())) + (s (add-to-store %store "bash" #t "sha256" + (search-bootstrap-binary "bash" + (%current-system)))) + (d (map (lambda (i) + (derivation %store (string-append "the-thing-" + (number->string i)) + s `("-e" ,b) + #:env-vars `(("foo" . ,(random-text))) + #:sources (list b s) + #:properties `((n . ,i)))) + (iota 20))) + (calls '())) + (define lst + (with-build-handler (lambda (continue store things mode) + (set! calls (cons things calls)) + (continue #f)) + (map/accumulate-builds %store + (lambda (d) + (build-derivations %store (list d)) + (assq-ref (derivation-properties d) 'n)) + d + #:cutoff 7))) + + (match (reverse calls) + (((batch1 ...) (batch2 ...) (batch3 ...)) + (and (equal? (map derivation-file-name (take d 8)) batch1) + (equal? (map derivation-file-name (take (drop d 8) 8)) batch2) + (equal? (map derivation-file-name (drop d 16)) batch3) + lst))))) + (test-assert "mapm/accumulate-builds" (let* ((d1 (run-with-store %store (gexp->derivation "foo" #~(mkdir #$output)))) diff --git a/tests/system.scm b/tests/system.scm index 9416b950e6..019c720e65 100644 --- a/tests/system.scm +++ b/tests/system.scm @@ -39,7 +39,7 @@ (locale "en_US.utf8") (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/sdX"))) + (targets '("/dev/sdX")))) (file-systems (cons %root-fs %base-file-systems)) (users %base-user-accounts))) @@ -56,7 +56,7 @@ (locale "en_US.utf8") (bootloader (bootloader-configuration (bootloader grub-bootloader) - (target "/dev/sdX"))) + (targets '("/dev/sdX")))) (mapped-devices (list %luks-device)) (file-systems (cons (file-system (inherit %root-fs) diff --git a/tests/transformations.scm b/tests/transformations.scm index 902bd45a6a..09839dc1c5 100644 --- a/tests/transformations.scm +++ b/tests/transformations.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2016, 2017, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2021 Marius Bakke <marius@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -29,7 +30,10 @@ #:use-module (guix build-system) #:use-module (guix build-system gnu) #:use-module (guix transformations) - #:use-module ((guix gexp) #:select (local-file? local-file-file)) + #:use-module ((guix gexp) + #:select (local-file? local-file-file + computed-file? computed-file-gexp + gexp-input-thing)) #:use-module (guix ui) #:use-module (guix utils) #:use-module (guix git) @@ -232,6 +236,26 @@ (string=? (package-name dep2) "chbouib") (package-source dep2)))))))) +(test-equal "options->transformation, with-commit, version transformation" + '("1.0" "1.0-rc1-2-gabc123" "git.abc123") + (map (lambda (commit) + (let* ((p (dummy-package "guix.scm" + (inputs `(("foo" ,(dummy-package "chbouib" + (source (origin + (method git-fetch) + (uri (git-reference + (url "https://example.org") + (commit "cabba9e"))) + (sha256 #f))))))))) + (t (options->transformation + `((with-commit . ,(string-append "chbouib=" commit)))))) + (let ((new (t p))) + (and (not (eq? new p)) + (match (package-inputs new) + ((("foo" dep1)) + (package-version dep1))))))) + '("v1.0" "1.0-rc1-2-gabc123" "abc123"))) + (test-equal "options->transformation, with-git-url" (let ((source (git-checkout (url "https://example.org") (recursive? #t)))) @@ -400,6 +424,31 @@ (map local-file-file (origin-patches (package-source dep))))))))) +(test-equal "options->transformation, with-commit + with-patch" + '(#t #t) + (let* ((patch (search-patch "glibc-locales.patch")) + (commit "f8934ec94df5868ee8baf1fb0f8ed0f24e7e91eb") + (t (options->transformation + ;; Note: options are applied in reverse order, so + ;; 'with-patch' comes on top. + `((with-patch . ,(string-append "guile-gcrypt=" patch)) + (with-commit + . ,(string-append "guile-gcrypt=" commit)))))) + (let ((new (t (@ (gnu packages gnupg) guile-gcrypt)))) + (match (package-source new) + ((? computed-file? source) + (let* ((gexp (computed-file-gexp source)) + (inputs (map gexp-input-thing + ((@@ (guix gexp) gexp-inputs) gexp)))) + (list (any (lambda (input) + (and (git-checkout? input) + (string=? commit (git-checkout-commit input)))) + inputs) + (any (lambda (input) + (and (local-file? input) + (string=? (local-file-file input) patch))) + inputs)))))))) + (test-equal "options->transformation, with-latest" "42.0" (mock ((guix upstream) %updaters |