diff options
Diffstat (limited to 'gnu/tests/base.scm')
| -rw-r--r-- | gnu/tests/base.scm | 468 |
1 files changed, 315 insertions, 153 deletions
diff --git a/gnu/tests/base.scm b/gnu/tests/base.scm index 4fe779802ba..479403e5c1a 100644 --- a/gnu/tests/base.scm +++ b/gnu/tests/base.scm | |||
| @@ -22,10 +22,15 @@ | |||
| 22 | #:use-module (gnu system grub) | 22 | #:use-module (gnu system grub) |
| 23 | #:use-module (gnu system file-systems) | 23 | #:use-module (gnu system file-systems) |
| 24 | #:use-module (gnu system shadow) | 24 | #:use-module (gnu system shadow) |
| 25 | #:use-module (gnu system nss) | ||
| 25 | #:use-module (gnu system vm) | 26 | #:use-module (gnu system vm) |
| 26 | #:use-module (gnu services) | 27 | #:use-module (gnu services) |
| 28 | #:use-module (gnu services base) | ||
| 29 | #:use-module (gnu services dbus) | ||
| 30 | #:use-module (gnu services avahi) | ||
| 27 | #:use-module (gnu services mcron) | 31 | #:use-module (gnu services mcron) |
| 28 | #:use-module (gnu services shepherd) | 32 | #:use-module (gnu services shepherd) |
| 33 | #:use-module (gnu services networking) | ||
| 29 | #:use-module (guix gexp) | 34 | #:use-module (guix gexp) |
| 30 | #:use-module (guix store) | 35 | #:use-module (guix store) |
| 31 | #:use-module (guix monads) | 36 | #:use-module (guix monads) |
| @@ -33,7 +38,8 @@ | |||
| 33 | #:use-module (srfi srfi-1) | 38 | #:use-module (srfi srfi-1) |
| 34 | #:export (run-basic-test | 39 | #:export (run-basic-test |
| 35 | %test-basic-os | 40 | %test-basic-os |
| 36 | %test-mcron)) | 41 | %test-mcron |
| 42 | %test-nss-mdns)) | ||
| 37 | 43 | ||
| 38 | (define %simple-os | 44 | (define %simple-os |
| 39 | (operating-system | 45 | (operating-system |
| @@ -64,104 +70,123 @@ | |||
| 64 | using COMMAND, a gexp that evaluates to a list of strings. Compare some | 70 | using COMMAND, a gexp that evaluates to a list of strings. Compare some |
| 65 | properties of running system to what's declared in OS, an <operating-system>." | 71 | properties of running system to what's declared in OS, an <operating-system>." |
| 66 | (define test | 72 | (define test |
| 67 | #~(begin | 73 | (with-imported-modules '((gnu build marionette)) |
| 68 | (use-modules (gnu build marionette) | 74 | #~(begin |
| 69 | (srfi srfi-1) | 75 | (use-modules (gnu build marionette) |
| 70 | (srfi srfi-26) | 76 | (srfi srfi-64) |
| 71 | (srfi srfi-64) | 77 | (ice-9 match)) |
| 72 | (ice-9 match)) | 78 | |
| 73 | 79 | (define marionette | |
| 74 | (define marionette | 80 | (make-marionette #$command)) |
| 75 | (make-marionette #$command)) | 81 | |
| 76 | 82 | (mkdir #$output) | |
| 77 | (mkdir #$output) | 83 | (chdir #$output) |
| 78 | (chdir #$output) | 84 | |
| 79 | 85 | (test-begin "mcron") | |
| 80 | (test-begin "basic") | 86 | |
| 81 | 87 | (test-assert "uname" | |
| 82 | (test-assert "uname" | 88 | (match (marionette-eval '(uname) marionette) |
| 83 | (match (marionette-eval '(uname) marionette) | 89 | (#("Linux" host-name version _ architecture) |
| 84 | (#("Linux" host-name version _ architecture) | 90 | (and (string=? host-name |
| 85 | (and (string=? host-name | 91 | #$(operating-system-host-name os)) |
| 86 | #$(operating-system-host-name os)) | 92 | (string-prefix? #$(package-version |
| 87 | (string-prefix? #$(package-version | 93 | (operating-system-kernel os)) |
| 88 | (operating-system-kernel os)) | 94 | version) |
| 89 | version) | 95 | (string-prefix? architecture %host-type))))) |
| 90 | (string-prefix? architecture %host-type))))) | 96 | |
| 91 | 97 | (test-assert "shell and user commands" | |
| 92 | (test-assert "shell and user commands" | 98 | ;; Is everything in $PATH? |
| 93 | ;; Is everything in $PATH? | 99 | (zero? (marionette-eval '(system " |
| 94 | (zero? (marionette-eval '(system " | ||
| 95 | . /etc/profile | 100 | . /etc/profile |
| 96 | set -e -x | 101 | set -e -x |
| 97 | guix --version | 102 | guix --version |
| 98 | ls --version | 103 | ls --version |
| 99 | grep --version | 104 | grep --version |
| 100 | info --version") | 105 | info --version") |
| 101 | marionette))) | 106 | marionette))) |
| 102 | 107 | ||
| 103 | (test-assert "accounts" | 108 | (test-assert "accounts" |
| 104 | (let ((users (marionette-eval '(begin | 109 | (let ((users (marionette-eval '(begin |
| 105 | (use-modules (ice-9 match)) | 110 | (use-modules (ice-9 match)) |
| 106 | (let loop ((result '())) | 111 | (let loop ((result '())) |
| 107 | (match (getpw) | 112 | (match (getpw) |
| 108 | (#f (reverse result)) | 113 | (#f (reverse result)) |
| 109 | (x (loop (cons x result)))))) | 114 | (x (loop (cons x result)))))) |
| 110 | marionette))) | 115 | marionette))) |
| 111 | (lset= string=? | 116 | (lset= string=? |
| 112 | (map passwd:name users) | 117 | (map passwd:name users) |
| 113 | (list | 118 | (list |
| 114 | #$@(map user-account-name | 119 | #$@(map user-account-name |
| 115 | (operating-system-user-accounts os)))))) | 120 | (operating-system-user-accounts os)))))) |
| 116 | 121 | ||
| 117 | (test-assert "shepherd services" | 122 | (test-assert "shepherd services" |
| 118 | (let ((services (marionette-eval '(begin | 123 | (let ((services (marionette-eval '(begin |
| 119 | (use-modules (gnu services herd)) | 124 | (use-modules (gnu services herd)) |
| 120 | (call-with-values current-services | 125 | (call-with-values current-services |
| 121 | append)) | 126 | append)) |
| 122 | marionette))) | 127 | marionette))) |
| 123 | (lset= eq? | 128 | (lset= eq? |
| 124 | (pk 'services services) | 129 | (pk 'services services) |
| 125 | '(root #$@(operating-system-shepherd-service-names os))))) | 130 | '(root #$@(operating-system-shepherd-service-names os))))) |
| 126 | 131 | ||
| 127 | (test-equal "login on tty1" | 132 | (test-equal "login on tty1" |
| 128 | "root\n" | 133 | "root\n" |
| 129 | (begin | 134 | (begin |
| 130 | (marionette-control "sendkey ctrl-alt-f1" marionette) | 135 | (marionette-control "sendkey ctrl-alt-f1" marionette) |
| 131 | ;; Wait for the 'term-tty1' service to be running (using | 136 | ;; Wait for the 'term-tty1' service to be running (using |
| 132 | ;; 'start-service' is the simplest and most reliable way to do | 137 | ;; 'start-service' is the simplest and most reliable way to do |
| 133 | ;; that.) | 138 | ;; that.) |
| 139 | (marionette-eval | ||
| 140 | '(begin | ||
| 141 | (use-modules (gnu services herd)) | ||
| 142 | (start-service 'term-tty1)) | ||
| 143 | marionette) | ||
| 144 | |||
| 145 | ;; Now we can type. | ||
| 146 | (marionette-type "root\n\nid -un > logged-in\n" marionette) | ||
| 147 | |||
| 148 | ;; It can take a while before the shell commands are executed. | ||
| 149 | (let loop ((i 0)) | ||
| 150 | (unless (or (file-exists? "/root/logged-in") (> i 15)) | ||
| 151 | (sleep 1) | ||
| 152 | (loop (+ i 1)))) | ||
| 153 | (marionette-eval '(use-modules (rnrs io ports)) marionette) | ||
| 154 | (marionette-eval '(call-with-input-file "/root/logged-in" | ||
| 155 | get-string-all) | ||
| 156 | marionette))) | ||
| 157 | |||
| 158 | (test-assert "host name resolution" | ||
| 159 | (match (marionette-eval | ||
| 160 | '(begin | ||
| 161 | ;; Wait for nscd or our requests go through it. | ||
| 162 | (use-modules (gnu services herd)) | ||
| 163 | (start-service 'nscd) | ||
| 164 | |||
| 165 | (list (getaddrinfo "localhost") | ||
| 166 | (getaddrinfo #$(operating-system-host-name os)))) | ||
| 167 | marionette) | ||
| 168 | ((((? vector?) ..1) ((? vector?) ..1)) | ||
| 169 | #t) | ||
| 170 | (x | ||
| 171 | (pk 'failure x #f)))) | ||
| 172 | |||
| 173 | (test-equal "host not found" | ||
| 174 | #f | ||
| 134 | (marionette-eval | 175 | (marionette-eval |
| 135 | '(begin | 176 | '(false-if-exception (getaddrinfo "does-not-exist")) |
| 136 | (use-modules (gnu services herd)) | 177 | marionette)) |
| 137 | (start-service 'term-tty1)) | 178 | |
| 138 | marionette) | 179 | (test-assert "screendump" |
| 139 | 180 | (begin | |
| 140 | ;; Now we can type. | 181 | (marionette-control (string-append "screendump " #$output |
| 141 | (marionette-type "root\n\nid -un > logged-in\n" marionette) | 182 | "/tty1.ppm") |
| 142 | 183 | marionette) | |
| 143 | ;; It can take a while before the shell commands are executed. | 184 | (file-exists? "tty1.ppm"))) |
| 144 | (let loop ((i 0)) | 185 | |
| 145 | (unless (or (file-exists? "/root/logged-in") (> i 15)) | 186 | (test-end) |
| 146 | (sleep 1) | 187 | (exit (= (test-runner-fail-count (test-runner-current)) 0))))) |
| 147 | (loop (+ i 1)))) | 188 | |
| 148 | (marionette-eval '(use-modules (rnrs io ports)) marionette) | 189 | (gexp->derivation name test)) |
| 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 | 190 | ||
| 166 | (define %test-basic-os | 191 | (define %test-basic-os |
| 167 | (system-test | 192 | (system-test |
| @@ -216,70 +241,207 @@ functionality tests.") | |||
| 216 | (command (system-qemu-image/shared-store-script | 241 | (command (system-qemu-image/shared-store-script |
| 217 | os #:graphic? #f))) | 242 | os #:graphic? #f))) |
| 218 | (define test | 243 | (define test |
| 219 | #~(begin | 244 | (with-imported-modules '((gnu build marionette)) |
| 220 | (use-modules (gnu build marionette) | 245 | #~(begin |
| 221 | (srfi srfi-64) | 246 | (use-modules (gnu build marionette) |
| 222 | (ice-9 match)) | 247 | (srfi srfi-64) |
| 223 | 248 | (ice-9 match)) | |
| 224 | (define marionette | 249 | |
| 225 | (make-marionette (list #$command))) | 250 | (define marionette |
| 226 | 251 | (make-marionette (list #$command))) | |
| 227 | (define (wait-for-file file) | 252 | |
| 228 | ;; Wait until FILE exists in the guest; 'read' its content and | 253 | (define (wait-for-file file) |
| 229 | ;; return it. | 254 | ;; Wait until FILE exists in the guest; 'read' its content and |
| 230 | (marionette-eval | 255 | ;; return it. |
| 231 | `(let loop ((i 10)) | 256 | (marionette-eval |
| 232 | (cond ((file-exists? ,file) | 257 | `(let loop ((i 10)) |
| 233 | (call-with-input-file ,file read)) | 258 | (cond ((file-exists? ,file) |
| 234 | ((> i 0) | 259 | (call-with-input-file ,file read)) |
| 235 | (sleep 1) | 260 | ((> i 0) |
| 236 | (loop (- i 1))) | 261 | (sleep 1) |
| 237 | (else | 262 | (loop (- i 1))) |
| 238 | (error "file didn't show up" ,file)))) | 263 | (else |
| 239 | marionette)) | 264 | (error "file didn't show up" ,file)))) |
| 240 | 265 | marionette)) | |
| 241 | (mkdir #$output) | 266 | |
| 242 | (chdir #$output) | 267 | (mkdir #$output) |
| 243 | 268 | (chdir #$output) | |
| 244 | (test-begin "mcron") | 269 | |
| 245 | 270 | (test-begin "mcron") | |
| 246 | (test-eq "service running" | 271 | |
| 247 | 'running! | 272 | (test-eq "service running" |
| 248 | (marionette-eval | 273 | 'running! |
| 249 | '(begin | 274 | (marionette-eval |
| 250 | (use-modules (gnu services herd)) | 275 | '(begin |
| 251 | (start-service 'mcron) | 276 | (use-modules (gnu services herd)) |
| 252 | 'running!) | 277 | (start-service 'mcron) |
| 253 | marionette)) | 278 | 'running!) |
| 254 | 279 | marionette)) | |
| 255 | ;; Make sure root's mcron job runs, has its cwd set to "/root", and | 280 | |
| 256 | ;; runs with the right UID/GID. | 281 | ;; Make sure root's mcron job runs, has its cwd set to "/root", and |
| 257 | (test-equal "root's job" | 282 | ;; runs with the right UID/GID. |
| 258 | '(0 0) | 283 | (test-equal "root's job" |
| 259 | (wait-for-file "/root/witness")) | 284 | '(0 0) |
| 260 | 285 | (wait-for-file "/root/witness")) | |
| 261 | ;; Likewise for Alice's job. We cannot know what its GID is since | 286 | |
| 262 | ;; it's chosen by 'groupadd', but it's strictly positive. | 287 | ;; Likewise for Alice's job. We cannot know what its GID is since |
| 263 | (test-assert "alice's job" | 288 | ;; it's chosen by 'groupadd', but it's strictly positive. |
| 264 | (match (wait-for-file "/home/alice/witness") | 289 | (test-assert "alice's job" |
| 265 | ((1000 gid) | 290 | (match (wait-for-file "/home/alice/witness") |
| 266 | (>= gid 100)))) | 291 | ((1000 gid) |
| 267 | 292 | (>= gid 100)))) | |
| 268 | ;; Last, the job that uses a command; allows us to test whether | 293 | |
| 269 | ;; $PATH is sane. (Note that 'marionette-eval' stringifies objects | 294 | ;; Last, the job that uses a command; allows us to test whether |
| 270 | ;; that don't have a read syntax, hence the string.) | 295 | ;; $PATH is sane. (Note that 'marionette-eval' stringifies objects |
| 271 | (test-equal "root's job with command" | 296 | ;; that don't have a read syntax, hence the string.) |
| 272 | "#<eof>" | 297 | (test-equal "root's job with command" |
| 273 | (wait-for-file "/root/witness-touch")) | 298 | "#<eof>" |
| 274 | 299 | (wait-for-file "/root/witness-touch")) | |
| 275 | (test-end) | 300 | |
| 276 | (exit (= (test-runner-fail-count (test-runner-current)) 0)))) | 301 | (test-end) |
| 277 | 302 | (exit (= (test-runner-fail-count (test-runner-current)) 0))))) | |
| 278 | (gexp->derivation name test | 303 | |
| 279 | #:modules '((gnu build marionette))))) | 304 | (gexp->derivation name test))) |
| 280 | 305 | ||
| 281 | (define %test-mcron | 306 | (define %test-mcron |
| 282 | (system-test | 307 | (system-test |
| 283 | (name "mcron") | 308 | (name "mcron") |
| 284 | (description "Make sure the mcron service works as advertised.") | 309 | (description "Make sure the mcron service works as advertised.") |
| 285 | (value (run-mcron-test name)))) | 310 | (value (run-mcron-test name)))) |
| 311 | |||
| 312 | |||
| 313 | ;;; | ||
| 314 | ;;; Avahi and NSS-mDNS. | ||
| 315 | ;;; | ||
| 316 | |||
| 317 | (define %avahi-os | ||
| 318 | (operating-system | ||
| 319 | (inherit %simple-os) | ||
| 320 | (name-service-switch %mdns-host-lookup-nss) | ||
| 321 | (services (cons* (avahi-service #:debug? #t) | ||
| 322 | (dbus-service) | ||
| 323 | (dhcp-client-service) ;needed for multicast | ||
| 324 | |||
| 325 | ;; Enable heavyweight debugging output. | ||
| 326 | (modify-services (operating-system-user-services | ||
| 327 | %simple-os) | ||
| 328 | (nscd-service-type config | ||
| 329 | => (nscd-configuration | ||
| 330 | (inherit config) | ||
| 331 | (debug-level 3) | ||
| 332 | (log-file "/dev/console"))) | ||
| 333 | (syslog-service-type config | ||
| 334 | => | ||
| 335 | (plain-file | ||
| 336 | "syslog.conf" | ||
| 337 | "*.* /dev/console\n"))))))) | ||
| 338 | |||
| 339 | (define (run-nss-mdns-test) | ||
| 340 | ;; Test resolution of '.local' names via libc. Start the marionette service | ||
| 341 | ;; *after* nscd. Failing to do that, libc will try to connect to nscd, | ||
| 342 | ;; fail, then never try again (see '__nss_not_use_nscd_hosts' in libc), | ||
| 343 | ;; leading to '.local' resolution failures. | ||
| 344 | (mlet* %store-monad ((os -> (marionette-operating-system | ||
| 345 | %avahi-os | ||
| 346 | #:requirements '(nscd) | ||
| 347 | #:imported-modules '((gnu services herd) | ||
| 348 | (guix combinators)))) | ||
| 349 | (run (system-qemu-image/shared-store-script | ||
| 350 | os #:graphic? #f))) | ||
| 351 | (define mdns-host-name | ||
| 352 | (string-append (operating-system-host-name os) | ||
| 353 | ".local")) | ||
| 354 | |||
| 355 | (define test | ||
| 356 | (with-imported-modules '((gnu build marionette)) | ||
| 357 | #~(begin | ||
| 358 | (use-modules (gnu build marionette) | ||
| 359 | (srfi srfi-1) | ||
| 360 | (srfi srfi-64) | ||
| 361 | (ice-9 match)) | ||
| 362 | |||
| 363 | (define marionette | ||
| 364 | (make-marionette (list #$run))) | ||
| 365 | |||
| 366 | (mkdir #$output) | ||
| 367 | (chdir #$output) | ||
| 368 | |||
| 369 | (test-begin "avahi") | ||
| 370 | |||
| 371 | (test-assert "wait for services" | ||
| 372 | (marionette-eval | ||
| 373 | '(begin | ||
| 374 | (use-modules (gnu services herd)) | ||
| 375 | |||
| 376 | (start-service 'nscd) | ||
| 377 | |||
| 378 | ;; XXX: Work around a race condition in nscd: nscd creates its | ||
| 379 | ;; PID file before it is listening on its socket. | ||
| 380 | (let ((sock (socket PF_UNIX SOCK_STREAM 0))) | ||
| 381 | (let try () | ||
| 382 | (catch 'system-error | ||
| 383 | (lambda () | ||
| 384 | (connect sock AF_UNIX "/var/run/nscd/socket") | ||
| 385 | (close-port sock) | ||
| 386 | (format #t "nscd is ready~%")) | ||
| 387 | (lambda args | ||
| 388 | (format #t "waiting for nscd...~%") | ||
| 389 | (usleep 500000) | ||
| 390 | (try))))) | ||
| 391 | |||
| 392 | ;; Wait for the other useful things. | ||
| 393 | (start-service 'avahi-daemon) | ||
| 394 | (start-service 'networking) | ||
| 395 | |||
| 396 | #t) | ||
| 397 | marionette)) | ||
| 398 | |||
| 399 | (test-equal "avahi-resolve-host-name" | ||
| 400 | 0 | ||
| 401 | (marionette-eval | ||
| 402 | '(system* | ||
| 403 | "/run/current-system/profile/bin/avahi-resolve-host-name" | ||
| 404 | "-v" #$mdns-host-name) | ||
| 405 | marionette)) | ||
| 406 | |||
| 407 | (test-equal "avahi-browse" | ||
| 408 | 0 | ||
| 409 | (marionette-eval | ||
| 410 | '(system* "avahi-browse" "-avt") | ||
| 411 | marionette)) | ||
| 412 | |||
| 413 | (test-assert "getaddrinfo .local" | ||
| 414 | ;; Wait for the 'avahi-daemon' service and perform a resolution. | ||
| 415 | (match (marionette-eval | ||
| 416 | '(getaddrinfo #$mdns-host-name) | ||
| 417 | marionette) | ||
| 418 | (((? vector? addrinfos) ..1) | ||
| 419 | (pk 'getaddrinfo addrinfos) | ||
| 420 | (and (any (lambda (ai) | ||
| 421 | (= AF_INET (addrinfo:fam ai))) | ||
| 422 | addrinfos) | ||
| 423 | (any (lambda (ai) | ||
| 424 | (= AF_INET6 (addrinfo:fam ai))) | ||
| 425 | addrinfos))))) | ||
| 426 | |||
| 427 | (test-assert "gethostbyname .local" | ||
| 428 | (match (pk 'gethostbyname | ||
| 429 | (marionette-eval '(gethostbyname #$mdns-host-name) | ||
| 430 | marionette)) | ||
| 431 | ((? vector? result) | ||
| 432 | (and (string=? (hostent:name result) #$mdns-host-name) | ||
| 433 | (= (hostent:addrtype result) AF_INET))))) | ||
| 434 | |||
| 435 | |||
| 436 | (test-end) | ||
| 437 | (exit (= (test-runner-fail-count (test-runner-current)) 0))))) | ||
| 438 | |||
| 439 | (gexp->derivation "nss-mdns" test))) | ||
| 440 | |||
| 441 | (define %test-nss-mdns | ||
| 442 | (system-test | ||
| 443 | (name "nss-mdns") | ||
| 444 | (description | ||
| 445 | "Test Avahi's multicast-DNS implementation, and in particular, test its | ||
| 446 | glibc name service switch (NSS) module.") | ||
| 447 | (value (run-nss-mdns-test)))) | ||
