tests: basic: Don't hard-code the expected architecture name.
[jackhill/guix/guix.git] / gnu / tests / base.scm
CommitLineData
e9f693d0
LC
1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2016 Ludovic Courtès <ludo@gnu.org>
3;;;
4;;; This file is part of GNU Guix.
5;;;
6;;; GNU Guix is free software; you can redistribute it and/or modify it
7;;; under the terms of the GNU General Public License as published by
8;;; the Free Software Foundation; either version 3 of the License, or (at
9;;; your option) any later version.
10;;;
11;;; GNU Guix is distributed in the hope that it will be useful, but
12;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18
19(define-module (gnu tests base)
20 #:use-module (gnu tests)
21 #:use-module (gnu system)
22 #:use-module (gnu system grub)
23 #:use-module (gnu system file-systems)
24 #:use-module (gnu system shadow)
25 #:use-module (gnu system vm)
26 #:use-module (gnu services)
c311089b 27 #:use-module (gnu services mcron)
e9f693d0
LC
28 #:use-module (gnu services shepherd)
29 #:use-module (guix gexp)
30 #:use-module (guix store)
31 #:use-module (guix monads)
32 #:use-module (guix packages)
33 #:use-module (srfi srfi-1)
e3de272a 34 #:export (run-basic-test
c311089b
LC
35 %test-basic-os
36 %test-mcron))
e9f693d0
LC
37
38(define %simple-os
39 (operating-system
40 (host-name "komputilo")
41 (timezone "Europe/Berlin")
42 (locale "en_US.UTF-8")
43
44 (bootloader (grub-configuration (device "/dev/sdX")))
45 (file-systems (cons (file-system
46 (device "my-root")
47 (title 'label)
48 (mount-point "/")
49 (type "ext4"))
50 %base-file-systems))
51 (firmware '())
52
53 (users (cons (user-account
54 (name "alice")
55 (comment "Bob's sister")
56 (group "users")
57 (supplementary-groups '("wheel" "audio" "video"))
58 (home-directory "/home/alice"))
59 %base-user-accounts))))
60
61\f
e3de272a
LC
62(define* (run-basic-test os command #:optional (name "basic"))
63 "Return a derivation called NAME that tests basic features of the OS started
64using COMMAND, a gexp that evaluates to a list of strings. Compare some
65properties of running system to what's declared in OS, an <operating-system>."
66 (define test
67 #~(begin
68 (use-modules (gnu build marionette)
69 (srfi srfi-1)
70 (srfi srfi-26)
71 (srfi srfi-64)
72 (ice-9 match))
73
74 (define marionette
75 (make-marionette #$command))
76
77 (mkdir #$output)
78 (chdir #$output)
79
80 (test-begin "basic")
81
82 (test-assert "uname"
83 (match (marionette-eval '(uname) marionette)
125af57e 84 (#("Linux" host-name version _ architecture)
908935b5
LC
85 (and (string=? host-name
86 #$(operating-system-host-name os))
87 (string-prefix? #$(package-version
88 (operating-system-kernel os))
125af57e
LC
89 version)
90 (string-prefix? architecture %host-type)))))
e3de272a
LC
91
92 (test-assert "shell and user commands"
93 ;; Is everything in $PATH?
94 (zero? (marionette-eval '(system "
95. /etc/profile
96set -e -x
97guix --version
98ls --version
99grep --version
100info --version")
101 marionette)))
102
103 (test-assert "accounts"
104 (let ((users (marionette-eval '(begin
105 (use-modules (ice-9 match))
106 (let loop ((result '()))
107 (match (getpw)
108 (#f (reverse result))
109 (x (loop (cons x result))))))
110 marionette)))
111 (lset= string=?
112 (map passwd:name users)
113 (list
114 #$@(map user-account-name
115 (operating-system-user-accounts os))))))
116
117 (test-assert "shepherd services"
118 (let ((services (marionette-eval '(begin
119 (use-modules (gnu services herd))
120 (call-with-values current-services
121 append))
122 marionette)))
123 (lset= eq?
124 (pk 'services services)
908935b5 125 '(root #$@(operating-system-shepherd-service-names os)))))
e3de272a
LC
126
127 (test-equal "login on tty1"
128 "root\n"
129 (begin
130 (marionette-control "sendkey ctrl-alt-f1" marionette)
131 ;; Wait for the 'term-tty1' service to be running (using
132 ;; 'start-service' is the simplest and most reliable way to do
133 ;; that.)
134 (marionette-eval
135 '(begin
136 (use-modules (gnu services herd))
137 (start-service 'term-tty1))
138 marionette)
139
140 ;; Now we can type.
141 (marionette-type "root\n\nid -un > logged-in\n" marionette)
142
143 ;; It can take a while before the shell commands are executed.
144 (let loop ((i 0))
145 (unless (or (file-exists? "/root/logged-in") (> i 15))
146 (sleep 1)
147 (loop (+ i 1))))
148 (marionette-eval '(use-modules (rnrs io ports)) marionette)
149 (marionette-eval '(call-with-input-file "/root/logged-in"
150 get-string-all)
151 marionette)))
152
153 (test-assert "screendump"
154 (begin
155 (marionette-control (string-append "screendump " #$output
156 "/tty1.ppm")
157 marionette)
158 (file-exists? "tty1.ppm")))
159
160 (test-end)
161 (exit (= (test-runner-fail-count (test-runner-current)) 0))))
162
163 (gexp->derivation name test
164 #:modules '((gnu build marionette))))
165
e9f693d0 166(define %test-basic-os
98b65b5f
LC
167 (system-test
168 (name "basic")
169 (description
125af57e 170 "Instrument %SIMPLE-OS, run it in a VM, and run a series of basic
98b65b5f
LC
171functionality tests.")
172 (value
173 (mlet* %store-monad ((os -> (marionette-operating-system
174 %simple-os
175 #:imported-modules '((gnu services herd)
176 (guix combinators))))
177 (run (system-qemu-image/shared-store-script
178 os #:graphic? #f)))
179 ;; XXX: Add call to 'virtualized-operating-system' to get the exact same
180 ;; set of services as the OS produced by
181 ;; 'system-qemu-image/shared-store-script'.
182 (run-basic-test (virtualized-operating-system os '())
183 #~(list #$run))))))
c311089b
LC
184
185\f
186;;;
187;;; Mcron.
188;;;
189
190(define %mcron-os
191 ;; System with an mcron service, with one mcron job for "root" and one mcron
192 ;; job for an unprivileged user (note: #:user is an 'mcron2' thing.)
193 (let ((job1 #~(job next-second-from
194 (lambda ()
195 (call-with-output-file "witness"
196 (lambda (port)
197 (display (list (getuid) (getgid)) port))))))
198 (job2 #~(job next-second-from
199 (lambda ()
200 (call-with-output-file "witness"
201 (lambda (port)
202 (display (list (getuid) (getgid)) port))))
203 #:user "alice"))
204 (job3 #~(job next-second-from ;to test $PATH
205 "touch witness-touch")))
206 (operating-system
207 (inherit %simple-os)
208 (services (cons (mcron-service (list job1 job2 job3))
209 (operating-system-user-services %simple-os))))))
210
211(define (run-mcron-test name)
212 (mlet* %store-monad ((os -> (marionette-operating-system
213 %mcron-os
214 #:imported-modules '((gnu services herd)
215 (guix combinators))))
216 (command (system-qemu-image/shared-store-script
217 os #:graphic? #f)))
218 (define test
219 #~(begin
220 (use-modules (gnu build marionette)
221 (srfi srfi-64)
222 (ice-9 match))
223
224 (define marionette
225 (make-marionette (list #$command)))
226
227 (define (wait-for-file file)
228 ;; Wait until FILE exists in the guest; 'read' its content and
229 ;; return it.
230 (marionette-eval
231 `(let loop ((i 10))
232 (cond ((file-exists? ,file)
233 (call-with-input-file ,file read))
234 ((> i 0)
235 (sleep 1)
236 (loop (- i 1)))
237 (else
238 (error "file didn't show up" ,file))))
239 marionette))
240
241 (mkdir #$output)
242 (chdir #$output)
243
244 (test-begin "mcron")
245
246 (test-eq "service running"
247 'running!
248 (marionette-eval
249 '(begin
250 (use-modules (gnu services herd))
251 (start-service 'mcron)
252 'running!)
253 marionette))
254
255 ;; Make sure root's mcron job runs, has its cwd set to "/root", and
256 ;; runs with the right UID/GID.
257 (test-equal "root's job"
258 '(0 0)
259 (wait-for-file "/root/witness"))
260
261 ;; Likewise for Alice's job. We cannot know what its GID is since
262 ;; it's chosen by 'groupadd', but it's strictly positive.
263 (test-assert "alice's job"
264 (match (wait-for-file "/home/alice/witness")
265 ((1000 gid)
266 (>= gid 100))))
267
268 ;; Last, the job that uses a command; allows us to test whether
269 ;; $PATH is sane. (Note that 'marionette-eval' stringifies objects
270 ;; that don't have a read syntax, hence the string.)
271 (test-equal "root's job with command"
272 "#<eof>"
273 (wait-for-file "/root/witness-touch"))
274
275 (test-end)
276 (exit (= (test-runner-fail-count (test-runner-current)) 0))))
277
278 (gexp->derivation name test
279 #:modules '((gnu build marionette)))))
280
281(define %test-mcron
282 (system-test
283 (name "mcron")
284 (description "Make sure the mcron service works as advertised.")
285 (value (run-mcron-test name))))