services: avahi: Add #:debug? parameter.
[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
858d372c
LC
153 (test-assert "host name resolution"
154 (match (marionette-eval
155 '(begin
156 ;; Wait for nscd or our requests go through it.
157 (use-modules (gnu services herd))
158 (start-service 'nscd)
159
160 (list (getaddrinfo "localhost")
161 (getaddrinfo #$(operating-system-host-name os))))
162 marionette)
163 ((((? vector?) ..1) ((? vector?) ..1))
164 #t)
165 (x
166 (pk 'failure x #f))))
167
168 (test-equal "host not found"
169 #f
170 (marionette-eval
171 '(false-if-exception (getaddrinfo "does-not-exist"))
172 marionette))
173
e3de272a
LC
174 (test-assert "screendump"
175 (begin
176 (marionette-control (string-append "screendump " #$output
177 "/tty1.ppm")
178 marionette)
179 (file-exists? "tty1.ppm")))
180
181 (test-end)
182 (exit (= (test-runner-fail-count (test-runner-current)) 0))))
183
184 (gexp->derivation name test
185 #:modules '((gnu build marionette))))
186
e9f693d0 187(define %test-basic-os
98b65b5f
LC
188 (system-test
189 (name "basic")
190 (description
125af57e 191 "Instrument %SIMPLE-OS, run it in a VM, and run a series of basic
98b65b5f
LC
192functionality tests.")
193 (value
194 (mlet* %store-monad ((os -> (marionette-operating-system
195 %simple-os
196 #:imported-modules '((gnu services herd)
197 (guix combinators))))
198 (run (system-qemu-image/shared-store-script
199 os #:graphic? #f)))
200 ;; XXX: Add call to 'virtualized-operating-system' to get the exact same
201 ;; set of services as the OS produced by
202 ;; 'system-qemu-image/shared-store-script'.
203 (run-basic-test (virtualized-operating-system os '())
204 #~(list #$run))))))
c311089b
LC
205
206\f
207;;;
208;;; Mcron.
209;;;
210
211(define %mcron-os
212 ;; System with an mcron service, with one mcron job for "root" and one mcron
213 ;; job for an unprivileged user (note: #:user is an 'mcron2' thing.)
214 (let ((job1 #~(job next-second-from
215 (lambda ()
216 (call-with-output-file "witness"
217 (lambda (port)
218 (display (list (getuid) (getgid)) port))))))
219 (job2 #~(job next-second-from
220 (lambda ()
221 (call-with-output-file "witness"
222 (lambda (port)
223 (display (list (getuid) (getgid)) port))))
224 #:user "alice"))
225 (job3 #~(job next-second-from ;to test $PATH
226 "touch witness-touch")))
227 (operating-system
228 (inherit %simple-os)
229 (services (cons (mcron-service (list job1 job2 job3))
230 (operating-system-user-services %simple-os))))))
231
232(define (run-mcron-test name)
233 (mlet* %store-monad ((os -> (marionette-operating-system
234 %mcron-os
235 #:imported-modules '((gnu services herd)
236 (guix combinators))))
237 (command (system-qemu-image/shared-store-script
238 os #:graphic? #f)))
239 (define test
240 #~(begin
241 (use-modules (gnu build marionette)
242 (srfi srfi-64)
243 (ice-9 match))
244
245 (define marionette
246 (make-marionette (list #$command)))
247
248 (define (wait-for-file file)
249 ;; Wait until FILE exists in the guest; 'read' its content and
250 ;; return it.
251 (marionette-eval
252 `(let loop ((i 10))
253 (cond ((file-exists? ,file)
254 (call-with-input-file ,file read))
255 ((> i 0)
256 (sleep 1)
257 (loop (- i 1)))
258 (else
259 (error "file didn't show up" ,file))))
260 marionette))
261
262 (mkdir #$output)
263 (chdir #$output)
264
265 (test-begin "mcron")
266
267 (test-eq "service running"
268 'running!
269 (marionette-eval
270 '(begin
271 (use-modules (gnu services herd))
272 (start-service 'mcron)
273 'running!)
274 marionette))
275
276 ;; Make sure root's mcron job runs, has its cwd set to "/root", and
277 ;; runs with the right UID/GID.
278 (test-equal "root's job"
279 '(0 0)
280 (wait-for-file "/root/witness"))
281
282 ;; Likewise for Alice's job. We cannot know what its GID is since
283 ;; it's chosen by 'groupadd', but it's strictly positive.
284 (test-assert "alice's job"
285 (match (wait-for-file "/home/alice/witness")
286 ((1000 gid)
287 (>= gid 100))))
288
289 ;; Last, the job that uses a command; allows us to test whether
290 ;; $PATH is sane. (Note that 'marionette-eval' stringifies objects
291 ;; that don't have a read syntax, hence the string.)
292 (test-equal "root's job with command"
293 "#<eof>"
294 (wait-for-file "/root/witness-touch"))
295
296 (test-end)
297 (exit (= (test-runner-fail-count (test-runner-current)) 0))))
298
299 (gexp->derivation name test
300 #:modules '((gnu build marionette)))))
301
302(define %test-mcron
303 (system-test
304 (name "mcron")
305 (description "Make sure the mcron service works as advertised.")
306 (value (run-mcron-test name))))