aboutsummaryrefslogtreecommitdiff
path: root/gnu/tests.scm
blob: 5d4a4f8062841627809c47046964d8a36f56e9f6 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2017 Tobias Geerinckx-Rice <me@tobias.gr>
;;;
;;; This file is part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (gnu tests)
  #:use-module (guix gexp)
  #:use-module (guix utils)
  #:use-module (guix records)
  #:use-module (gnu bootloader)
  #:use-module (gnu bootloader grub)
  #:use-module (gnu system)
  #:use-module (gnu system file-systems)
  #:use-module (gnu system shadow)
  #:use-module (gnu services)
  #:use-module (gnu services base)
  #:use-module (gnu services shepherd)
  #:use-module (guix discovery)
  #:use-module (srfi srfi-1)
  #:use-module (srfi srfi-9 gnu)
  #:use-module (ice-9 match)
  #:export (marionette-configuration
            marionette-configuration?
            marionette-configuration-device
            marionette-configuration-imported-modules
            marionette-configuration-requirements

            marionette-service-type
            marionette-operating-system
            define-os-with-source

            simple-operating-system

            system-test
            system-test?
            system-test-name
            system-test-value
            system-test-description
            system-test-location

            fold-system-tests
            all-system-tests))

;;; Commentary:
;;;
;;; This module provides the infrastructure to run operating system tests.
;;; The most important part of that is tools to instrument the OS under test,
;;; essentially allowing to run in a virtual machine controlled by the host
;;; system--hence the name "marionette".
;;;
;;; Code:

(define-record-type* <marionette-configuration>
  marionette-configuration make-marionette-configuration
  marionette-configuration?
  (device           marionette-configuration-device ;string
                    (default "/dev/virtio-ports/org.gnu.guix.port.0"))
  (imported-modules marionette-configuration-imported-modules
                    (default '()))
  (requirements     marionette-configuration-requirements ;list of symbols
                    (default '())))

(define (marionette-shepherd-service config)
  "Return the Shepherd service for the marionette REPL"
  (match config
    (($ <marionette-configuration> device imported-modules requirement)
     (list (shepherd-service
            (provision '(marionette))

            ;; Always depend on UDEV so that DEVICE is available.
            (requirement `(udev ,@requirement))

            (modules '((ice-9 match)
                       (srfi srfi-9 gnu)
                       (rnrs bytevectors)))
            (start
             (with-imported-modules imported-modules
               #~(lambda ()
                   (define (self-quoting? x)
                     (letrec-syntax ((one-of (syntax-rules ()
                                               ((_) #f)
                                               ((_ pred rest ...)
                                                (or (pred x)
                                                    (one-of rest ...))))))
                       (one-of symbol? string? pair? null? vector?
                               bytevector? number? boolean?)))

                   (match (primitive-fork)
                     (0
                      (dynamic-wind
                        (const #t)
                        (lambda ()
                          (let ((repl    (open-file #$device "r+0"))
                                (console (open-file "/dev/console" "r+0")))
                            ;; Redirect output to the console.
                            (close-fdes 1)
                            (close-fdes 2)
                            (dup2 (fileno console) 1)
                            (dup2 (fileno console) 2)
                            (close-port console)

                            (display 'ready repl)
                            (let loop ()
                              (newline repl)

                              (match (read repl)
                                ((? eof-object?)
                                 (primitive-exit 0))
                                (expr
                                 (catch #t
                                   (lambda ()
                                     (let ((result (primitive-eval expr)))
                                       (write (if (self-quoting? result)
                                                  result
                                                  (object->string result))
                                              repl)))
                                   (lambda (key . args)
                                     (print-exception (current-error-port)
                                                      (stack-ref (make-stack #t) 1)
                                                      key args)
                                     (write #f repl)))))
                              (loop))))
                        (lambda ()
                          (primitive-exit 1))))
                     (pid
                      pid)))))
            (stop #~(make-kill-destructor)))))))

(define marionette-service-type
  ;; This is the type of the "marionette" service, allowing a guest system to
  ;; be manipulated from the host.  This marionette REPL is essentially a
  ;; universal backdoor.
  (service-type (name 'marionette-repl)
                (extensions
                 (list (service-extension shepherd-root-service-type
                                          marionette-shepherd-service)))))

(define* (marionette-operating-system os
                                      #:key
                                      (imported-modules '())
                                      (requirements '()))
  "Return a marionetteed variant of OS such that OS can be used as a
marionette in a virtual machine--i.e., controlled from the host system.  The
marionette service in the guest is started after the Shepherd services listed
in REQUIREMENTS."
  (operating-system
    (inherit os)
    ;; Make sure the guest dies on error.
    (kernel-arguments (cons "panic=1"
                            (operating-system-user-kernel-arguments os)))
    ;; Make sure the guest doesn't hang in the REPL on error.
    (initrd (lambda (fs . rest)
              (apply (operating-system-initrd os) fs
                     #:on-error 'backtrace
                     rest)))
    (services (cons (service marionette-service-type
                             (marionette-configuration
                              (requirements requirements)
                              (imported-modules imported-modules)))
                    (operating-system-user-services os)))))

(define-syntax define-os-with-source
  (syntax-rules (use-modules operating-system)
    "Define two variables: OS containing the given operating system, and
SOURCE containing the source to define OS as an sexp.

This is convenient when we need both the <operating-system> object so we can
instantiate it, and the source to create it so we can store in in a file in
the system under test."
    ((_ (os source)
        (use-modules modules ...)
        (operating-system fields ...))
     (begin
       (define os
         (operating-system fields ...))
       (define source
         '(begin
            (use-modules modules ...)
            (operating-system fields ...)))))))


;;;
;;; Simple operating systems.
;;;

(define %simple-os
  (operating-system
    (host-name "komputilo")
    (timezone "Europe/Berlin")
    (locale "en_US.UTF-8")

    (bootloader (bootloader-configuration
                 (bootloader grub-bootloader)
                 (target "/dev/sdX")))
    (file-systems (cons (file-system
                          (device (file-system-label "my-root"))
                          (mount-point "/")
                          (type "ext4"))
                        %base-file-systems))
    (firmware '())

    (users (cons (user-account
                  (name "alice")
                  (comment "Bob's sister")
                  (group "users")
                  (supplementary-groups '("wheel" "audio" "video"))
                  (home-directory "/home/alice"))
                 %base-user-accounts))))

(define-syntax-rule (simple-operating-system user-services ...)
  "Return an operating system that includes USER-SERVICES in addition to
%BASE-SERVICES."
  (operating-system (inherit %simple-os)
                    (services (cons* user-services ... %base-services))))



;;;
;;; Tests.
;;;

(define-record-type* <system-test> system-test make-system-test
  system-test?
  (name        system-test-name)                  ;string
  (value       system-test-value)                 ;%STORE-MONAD value
  (description system-test-description)           ;string
  (location    system-test-location (innate)      ;<location>
               (default (and=> (current-source-location)
                               source-properties->location))))

(define (write-system-test test port)
  (match test
    (($ <system-test> name _ _ ($ <location> file line))
     (format port "#<system-test ~a ~a:~a ~a>"
             name file line
             (number->string (object-address test) 16)))
    (($ <system-test> name)
     (format port "#<system-test ~a ~a>" name
             (number->string (object-address test) 16)))))

(set-record-type-printer! <system-test> write-system-test)

(define (test-modules)
  "Return the list of modules that define system tests."
  (scheme-modules (dirname (search-path %load-path "guix.scm"))
                  "gnu/tests"))

(define (fold-system-tests proc seed)
  "Invoke PROC on each system test, passing it the test and the previous
result."
  (fold-module-public-variables (lambda (obj result)
                                  (if (system-test? obj)
                                      (cons obj result)
                                      result))
                                '()
                                (test-modules)))

(define (all-system-tests)
  "Return the list of system tests."
  (reverse (fold-system-tests cons '())))

;;; tests.scm ends here
ariable. [dependencies]: Add it. [*core-modules*]: Remove #:libgcrypt from 'make-config.scm' call. Add #:extensions. [*config*]: Remove #:libgcrypt from 'make-config.scm' call. (%dependency-variables): Remove %libgcrypt. (make-config.scm): Remove #:libgcrypt. * build-aux/build-self.scm (guile-gcrypt): New variable. (make-config.scm): Remove #:libgcrypt. (build-program)[fake-gcrypt-hash]: New variable. Add (gcrypt hash) to the imported modules. Adjust load path assignments. * gnu/packages/package-management.scm (guix)[propagated-inputs]: Add GUILE-GCRYPT. [arguments]: In 'wrap-program' phase, add GUILE-GCRYPT to the search path. Ludovic Courtès 2018-09-04inferior: Add home-page and location package accessors....* guix/inferior.scm (inferior-package-home-page) (inferior-package-location): New procedures. * tests/inferior.scm ("inferior-packages"): Test them. Ludovic Courtès 2018-08-31records: Adjust to test changes in 'record-abi-mismatch-error'....Fixes a test failure introduced in de5cbd4a38a33e0412f1c481fe8e01a871dc13e5. * guix/records.scm (abi-check): Refer to TYPE in an unquoted context so we get at the RTD. * tests/records.scm ("ABI checks"): Adjust 'catch' handler to changes in the 'record-abi-mismatch-error' arguments. Ludovic Courtès 2018-08-24import: cpan: Adjust test to new URL....This is a followup to 9aba9b127840a116c806a2cbac901cf8077abcd0. * tests/cpan.scm ("cpan->guix-package"): Adjust 'home-page' URL. Ludovic Courtès 2018-08-24grafts: Add (guix build debug-link) and use it....Fixes <https://bugs.gnu.org/19973>. Reported by Mark H Weaver <mhw@netris.org>. * guix/build/debug-link.scm: New file. * guix/build/graft.scm (%graft-hooks): New variable. (graft): Add #:hooks and honor it. * guix/grafts.scm (graft-derivation/shallow): Add (guix build debug-link) and (guix elf) to #:modules. * tests/debug-link.scm: New file. * Makefile.am (MODULES): Add guix/build/debug-link.scm. (SCM_TESTS): Add tests/debug-link.scm. Ludovic Courtès 2018-08-21gremlin: 'elf-dynamic-info-needed' test is no longer skipped....* tests/gremlin.scm (%guile-executable): Use /proc/self/exe instead of (command-line). For a while now, the first element of (command-line) was "./build-aux/test-driver.scm"; consequently the test was always skipped. Ludovic Courtès 2018-07-24import: PyPI: Update redirected URL....* guix/import/pypi.scm (guix-package->pypi-name, pypi->guix-package): Update docstrings. (pypi-package?): Test for pypi.org, too. (pypi-fetch): s/pypi.python.org/pypi.org/ * tests/pypi.scm ("guix-package->pypi-name, new URL style", "pypi->guix-package", "pypi->guix-package, wheels"): Likewise. Marius Bakke 2018-07-20database: Reset timestamps to one second after the Epoch....Previously, store items registered in the database by this code (for instance, store items retrieved by 'guix offload' and passed to 'restore-file-set') would have an mtime of 0 instead of 1. This would cause problems for things like .go files: Guile would consider them to be older than the corresponding .scm file, and consequently it would ignore them and possibly use another (incorrect) .go file. Reported by Ricardo Wurmus. * guix/store/database.scm (reset-timestamps): Pass 1, not 0, to 'utime'. * tests/store-database.scm ("register-path"): Check the mtime of FILE and REF. Ludovic Courtès 2018-07-19hash: sha256 port now implements 'port-position'....* guix/hash.scm (open-sha256-port)[position]: New variable. [get-position]: New procedure. Pass it to 'make-custom-binary-output-port'. * tests/hash.scm ("open-sha256-port, hello"): Test 'port-position'. Ludovic Courtès 2018-07-19gexp: 'imported-files/derivation' can copy files instead of symlinking....* guix/gexp.scm (imported-files/derivation): Add #:symlink? and honor it. (imported-files): Pass #:symlink? to 'imported-files/derivation'. * tests/gexp.scm ("imported-files with file-like objects"): Add 'file=?' and use it instead of calling 'readlink'. Ludovic Courtès 2018-07-19gexp: 'imported-files' no longer creates a derivation by default....* guix/gexp.scm (gexp->derivation): Add #:import-creates-derivation?. Pass #:derivation? to 'imported-modules' and 'compiled-modules'. In -L argument, check whether MODULES is a derivation. (%not-slash): New variable. (file-mapping->tree): New procedure. (imported-files): Rename to... (imported-files/derivation): ... this. (imported-files): New procedure. Rewrite in terms of 'interned-file-tree' when possible; add #:derivation? parameter. (imported-modules, compiled-modules): Add #:derivation? parameter and pass it to 'imported-files'. * guix/packages.scm (patch-and-repack): Pass #:import-creates-derivation? to 'gexp->derivation'. * tests/gexp.scm ("imported-files"): Adjust to no longer expect a derivation. Ludovic Courtès 2018-07-19store: Add 'add-file-tree-to-store'....* guix/store.scm (%not-slash): New variable. (add-file-tree-to-store, interned-file-tree): New procedures. * tests/store.scm ("add-file-tree-to-store"): New test. Ludovic Courtès 2018-07-19serialization: Add 'write-file-tree'....* guix/serialization.scm (write-contents-from-port): New procedure. (write-contents): Write in terms of 'write-contents-from-port'. (filter/sort-directory-entries, write-file-tree): New procedures. (write-file): Rewrite in terms of 'write-file-tree'. * tests/nar.scm ("write-file-tree + restore-file"): New test. Ludovic Courtès 2018-07-13tests: Don't rely on temporary directories being permanent....* tests/gexp.scm ("gexp->script #:module-path", "program-file #:module-path"): Use run-with-store. Leo Famulari 2018-07-13Add (guix inferior) and (guix scripts repl)....* guix/inferior.scm, guix/scripts/repl.scm, tests/inferior.scm: New files. * Makefile.am (MODULES): Add 'guix/scripts/repl.scm' and 'guix/inferior.scm'. (SCM_TESTS): Add 'tests/inferior.scm'. * doc/guix.texi (Invoking guix repl): New node. Ludovic Courtès 2018-07-13guix package: Use relative symlinks to generations....Reported by Roel Janssen <roel@gnu.org> at <https://lists.gnu.org/archive/html/guix-devel/2018-07/msg00036.html>. * guix/profiles.scm (switch-to-generation): Use (basename generation) as the symlink target. * guix/scripts/package.scm (build-and-use-profile): Likewise, use (basename name) as the symlink target. * tests/guix-package.sh: Adjust --roll-back test accordingly. Add explicitly test with '-p foo/prof'. Ludovic Courtès 2018-07-12import: hackage: Evaluate "-any" and "-none" version comparison operators....* guix/import/cabal.scm (eval-cabal): Modify. * tests/hackage.scm (test-cabal-4): New variable and test. (test-cabal-5): New variable and test. (test-cabal-6): New variable and test. Danny Milosavljevic 2018-07-11import: gem: Add recursive import....* doc/guix.texi (Invoking guix import): Document gem recursive import. * guix/import/gem.scm (gem->guix-package): Return package and dependencies values. (gem-recursive-import): New procedure. * guix/scripts/import/gem.scm (show-help, %options): Add recursive option. (guix-import-gem): Use 'gem-recursive-import'. * tests/gem.scm (test-json): Rename to 'test-foo-json'. ("gem->guix-package"): Use 'test-foo-json'. (test-bar-json, test-bundler-json): New variables. ("gem-recursive-import"): New test. Oleg Pykhalov 2018-07-10guix: Add opam importer....* guix/scripts/import.scm (importers): Add opam. * guix/scripts/import/opam.scm: New file. * guix/import/opam.scm: New file. * tests/opam.scm: New file. * Makefile.am: Add them. * doc/guix.texi (Invoking guix import): Document it. Julien Lepiller 2018-07-05tests: Skip 'guix-pack.sh'....This works around a regression introduced in commit 66e9944e078cbb9e0d618377dd6df6e639640efa while waiting for a proper fix. * tests/guix-pack.sh: Add "exit 77". Ludovic Courtès 2018-07-03syscalls: Define AT_SYMLINK_NOFOLLOW et al....* guix/build/syscalls.scm (AT_FDCWD, AT_SYMLINK_NOFOLLOW, AT_REMOVEDIR) (AT_SYMLINK_FOLLOW, AT_NO_AUTOMOUNT, AT_EMPTY_PATH): New variables. * tests/syscalls.scm ("utime with AT_SYMLINK_NOFOLLOW"): New test. Ludovic Courtès 2018-07-03deduplication: Place link files under /gnu/store/.links....Previously they'd always be placed next to TO-REPLACE, which would lead to EPERM in some cases. * guix/store/deduplication.scm (replace-with-link): Add #:swap-directory parameter and honor it. Add call to 'make-file-writable'. Catch 'system-error' around 'rename-file'. (deduplicate): Pass #:swap-directory and remove uses of 'false-if-system-error'. * tests/store-deduplication.scm ("deduplicate"): Add 'chmod' call. Ludovic Courtès 2018-06-21system: Mapped devices needed for boot do not yield Shepherd services....Fixes <https://bugs.gnu.org/31889>. Reported by Taylan Kammer <taylanbayirli@gmail.com>. * gnu/system.scm (non-boot-file-system-service)[mapped-devices-for-boot]: New variable. Remove dependencies of FS that are members of MAPPED-DEVICES-FOR-BOOT. (mapped-device-user): Rename to... (mapped-device-users): ... this. Use 'filter' instead of 'find'. (operating-system-user-mapped-devices) (operating-system-boot-mapped-devices): Use 'any file-system-needed-for-boot?' instead of looking at the first user. * tests/system.scm ("non-boot-file-system-service"): New test. Ludovic Courtès 2018-06-14Remove 'guix-register' and its traces....* Makefile.am (SH_TESTS): Remove tests/guix-register.sh. * build-aux/pre-inst-env.in (GUIX_REGISTER): Remove. * gnu/build/install.scm (directives): Remove outdated comment. * gnu/build/vm.scm (root-partition-initializer): Update comment. * gnu/packages/package-management.scm (guix-register): Remove. * guix/config.scm.in (%sbindir, %guix-register-program): Remove. * guix/scripts/system.scm (install): Adjust docstring. * guix/self.scm (make-config.scm): Remove #:guix. Do not generate %sbindir and %guix-register-program. (specification->package): Remove "guix". * nix/guix-register/guix-register.cc: Remove. * nix/libstore/store-api.cc (decodeValidPathInfo): Remove. * nix/libstore/store-api.hh (decodeValidPathInfo): Remove declaration. * nix/local.mk (sbin_PROGRAMS, guix_register_SOURCES) (guix_register_CPPFLAGS, guix_register_LDFLAGS): Remove. * tests/guix-register.sh: Remove. Ludovic Courtès 2018-06-14store: Remove 'register-path'....* guix/store.scm (register-path): Remove. * guix/nar.scm: Use (guix store database). * guix/scripts/system.scm: Likewise. * tests/store-database.scm: Remove #:hide (register-path). * tests/store.scm ("register-path"): Remove. Ludovic Courtès 2018-06-14database: 'sqlite-register' takes a database, not a file name....* guix/store/database.scm (sqlite-register): Remove #:db-file and add 'db' parameter. Remove #:schema and 'parameterize'. (register-path): Wrap 'sqlite-register' call in 'with-database' and in 'parameterize'. * tests/store-database.scm ("new database") ("register-path with unregistered references"): Adjust accordingly. Ludovic Courtès