tests: Use 'virtual-machine' records instead of monadic procedures.
* gnu/tests/base.scm (%test-basic-os): Use 'let*' instead of 'mlet*' and 'virtual-machine' instead of 'system-qemu-image/shared-store-script'. (run-mcron-test): Likewise. (run-nss-mdns-test): Likewise. * gnu/tests/dict.scm (run-dicod-test): Likewise. * gnu/tests/mail.scm (run-opensmtpd-test): Likewise. (run-exim-test): Likewise. * gnu/tests/messaging.scm (run-xmpp-test): Likewise. * gnu/tests/networking.scm (run-inetd-test): Likewise. * gnu/tests/nfs.scm (run-nfs-test): Likewise. * gnu/tests/ssh.scm (run-ssh-test): Likewise. * gnu/tests/web.scm (run-nginx-test): Likewise.master
parent
ed419fa0c5
commit
8b113790fa
|
@ -34,7 +34,6 @@
|
|||
#:use-module (gnu packages package-management)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix store)
|
||||
#:use-module (guix monads)
|
||||
#:use-module (guix packages)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:export (run-basic-test
|
||||
|
@ -393,17 +392,16 @@ info --version")
|
|||
"Instrument %SIMPLE-OS, run it in a VM, and run a series of basic
|
||||
functionality tests.")
|
||||
(value
|
||||
(mlet* %store-monad ((os -> (marionette-operating-system
|
||||
%simple-os
|
||||
#:imported-modules '((gnu services herd)
|
||||
(guix combinators))))
|
||||
(run (system-qemu-image/shared-store-script
|
||||
os #:graphic? #f)))
|
||||
(let* ((os (marionette-operating-system
|
||||
%simple-os
|
||||
#:imported-modules '((gnu services herd)
|
||||
(guix combinators))))
|
||||
(vm (virtual-machine os)))
|
||||
;; XXX: Add call to 'virtualized-operating-system' to get the exact same
|
||||
;; set of services as the OS produced by
|
||||
;; 'system-qemu-image/shared-store-script'.
|
||||
(run-basic-test (virtualized-operating-system os '())
|
||||
#~(list #$run))))))
|
||||
#~(list #$vm))))))
|
||||
|
||||
|
||||
;;;
|
||||
|
@ -430,60 +428,60 @@ functionality tests.")
|
|||
(mcron-service (list job1 job2 job3)))))
|
||||
|
||||
(define (run-mcron-test name)
|
||||
(mlet* %store-monad ((os -> (marionette-operating-system
|
||||
%mcron-os
|
||||
#:imported-modules '((gnu services herd)
|
||||
(guix combinators))))
|
||||
(command (system-qemu-image/shared-store-script
|
||||
os #:graphic? #f)))
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (gnu build marionette)
|
||||
(srfi srfi-64)
|
||||
(ice-9 match))
|
||||
(define os
|
||||
(marionette-operating-system
|
||||
%mcron-os
|
||||
#:imported-modules '((gnu services herd)
|
||||
(guix combinators))))
|
||||
|
||||
(define marionette
|
||||
(make-marionette (list #$command)))
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (gnu build marionette)
|
||||
(srfi srfi-64)
|
||||
(ice-9 match))
|
||||
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
(define marionette
|
||||
(make-marionette (list #$(virtual-machine os))))
|
||||
|
||||
(test-begin "mcron")
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
|
||||
(test-eq "service running"
|
||||
'running!
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'mcron)
|
||||
'running!)
|
||||
marionette))
|
||||
(test-begin "mcron")
|
||||
|
||||
;; Make sure root's mcron job runs, has its cwd set to "/root", and
|
||||
;; runs with the right UID/GID.
|
||||
(test-equal "root's job"
|
||||
'(0 0)
|
||||
(wait-for-file "/root/witness" marionette))
|
||||
(test-eq "service running"
|
||||
'running!
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'mcron)
|
||||
'running!)
|
||||
marionette))
|
||||
|
||||
;; Likewise for Alice's job. We cannot know what its GID is since
|
||||
;; it's chosen by 'groupadd', but it's strictly positive.
|
||||
(test-assert "alice's job"
|
||||
(match (wait-for-file "/home/alice/witness" marionette)
|
||||
((1000 gid)
|
||||
(>= gid 100))))
|
||||
;; Make sure root's mcron job runs, has its cwd set to "/root", and
|
||||
;; runs with the right UID/GID.
|
||||
(test-equal "root's job"
|
||||
'(0 0)
|
||||
(wait-for-file "/root/witness" marionette))
|
||||
|
||||
;; Last, the job that uses a command; allows us to test whether
|
||||
;; $PATH is sane. (Note that 'marionette-eval' stringifies objects
|
||||
;; that don't have a read syntax, hence the string.)
|
||||
(test-equal "root's job with command"
|
||||
"#<eof>"
|
||||
(wait-for-file "/root/witness-touch" marionette))
|
||||
;; Likewise for Alice's job. We cannot know what its GID is since
|
||||
;; it's chosen by 'groupadd', but it's strictly positive.
|
||||
(test-assert "alice's job"
|
||||
(match (wait-for-file "/home/alice/witness" marionette)
|
||||
((1000 gid)
|
||||
(>= gid 100))))
|
||||
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
;; Last, the job that uses a command; allows us to test whether
|
||||
;; $PATH is sane. (Note that 'marionette-eval' stringifies objects
|
||||
;; that don't have a read syntax, hence the string.)
|
||||
(test-equal "root's job with command"
|
||||
"#<eof>"
|
||||
(wait-for-file "/root/witness-touch" marionette))
|
||||
|
||||
(gexp->derivation name test)))
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
|
||||
(gexp->derivation name test))
|
||||
|
||||
(define %test-mcron
|
||||
(system-test
|
||||
|
@ -526,102 +524,102 @@ functionality tests.")
|
|||
;; *after* nscd. Failing to do that, libc will try to connect to nscd,
|
||||
;; fail, then never try again (see '__nss_not_use_nscd_hosts' in libc),
|
||||
;; leading to '.local' resolution failures.
|
||||
(mlet* %store-monad ((os -> (marionette-operating-system
|
||||
%avahi-os
|
||||
#:requirements '(nscd)
|
||||
#:imported-modules '((gnu services herd)
|
||||
(guix combinators))))
|
||||
(run (system-qemu-image/shared-store-script
|
||||
os #:graphic? #f)))
|
||||
(define mdns-host-name
|
||||
(string-append (operating-system-host-name os)
|
||||
".local"))
|
||||
(define os
|
||||
(marionette-operating-system
|
||||
%avahi-os
|
||||
#:requirements '(nscd)
|
||||
#:imported-modules '((gnu services herd)
|
||||
(guix combinators))))
|
||||
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (gnu build marionette)
|
||||
(srfi srfi-1)
|
||||
(srfi srfi-64)
|
||||
(ice-9 match))
|
||||
(define mdns-host-name
|
||||
(string-append (operating-system-host-name os)
|
||||
".local"))
|
||||
|
||||
(define marionette
|
||||
(make-marionette (list #$run)))
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (gnu build marionette)
|
||||
(srfi srfi-1)
|
||||
(srfi srfi-64)
|
||||
(ice-9 match))
|
||||
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
(define marionette
|
||||
(make-marionette (list #$(virtual-machine os))))
|
||||
|
||||
(test-begin "avahi")
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
|
||||
(test-assert "wait for services"
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(test-begin "avahi")
|
||||
|
||||
(start-service 'nscd)
|
||||
(test-assert "wait for services"
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
|
||||
;; XXX: Work around a race condition in nscd: nscd creates its
|
||||
;; PID file before it is listening on its socket.
|
||||
(let ((sock (socket PF_UNIX SOCK_STREAM 0)))
|
||||
(let try ()
|
||||
(catch 'system-error
|
||||
(lambda ()
|
||||
(connect sock AF_UNIX "/var/run/nscd/socket")
|
||||
(close-port sock)
|
||||
(format #t "nscd is ready~%"))
|
||||
(lambda args
|
||||
(format #t "waiting for nscd...~%")
|
||||
(usleep 500000)
|
||||
(try)))))
|
||||
(start-service 'nscd)
|
||||
|
||||
;; Wait for the other useful things.
|
||||
(start-service 'avahi-daemon)
|
||||
(start-service 'networking)
|
||||
;; XXX: Work around a race condition in nscd: nscd creates its
|
||||
;; PID file before it is listening on its socket.
|
||||
(let ((sock (socket PF_UNIX SOCK_STREAM 0)))
|
||||
(let try ()
|
||||
(catch 'system-error
|
||||
(lambda ()
|
||||
(connect sock AF_UNIX "/var/run/nscd/socket")
|
||||
(close-port sock)
|
||||
(format #t "nscd is ready~%"))
|
||||
(lambda args
|
||||
(format #t "waiting for nscd...~%")
|
||||
(usleep 500000)
|
||||
(try)))))
|
||||
|
||||
#t)
|
||||
marionette))
|
||||
;; Wait for the other useful things.
|
||||
(start-service 'avahi-daemon)
|
||||
(start-service 'networking)
|
||||
|
||||
(test-equal "avahi-resolve-host-name"
|
||||
0
|
||||
(marionette-eval
|
||||
'(system*
|
||||
"/run/current-system/profile/bin/avahi-resolve-host-name"
|
||||
"-v" #$mdns-host-name)
|
||||
marionette))
|
||||
#t)
|
||||
marionette))
|
||||
|
||||
(test-equal "avahi-browse"
|
||||
0
|
||||
(marionette-eval
|
||||
'(system* "avahi-browse" "-avt")
|
||||
marionette))
|
||||
(test-equal "avahi-resolve-host-name"
|
||||
0
|
||||
(marionette-eval
|
||||
'(system*
|
||||
"/run/current-system/profile/bin/avahi-resolve-host-name"
|
||||
"-v" #$mdns-host-name)
|
||||
marionette))
|
||||
|
||||
(test-assert "getaddrinfo .local"
|
||||
;; Wait for the 'avahi-daemon' service and perform a resolution.
|
||||
(match (marionette-eval
|
||||
'(getaddrinfo #$mdns-host-name)
|
||||
marionette)
|
||||
(((? vector? addrinfos) ..1)
|
||||
(pk 'getaddrinfo addrinfos)
|
||||
(and (any (lambda (ai)
|
||||
(= AF_INET (addrinfo:fam ai)))
|
||||
addrinfos)
|
||||
(any (lambda (ai)
|
||||
(= AF_INET6 (addrinfo:fam ai)))
|
||||
addrinfos)))))
|
||||
(test-equal "avahi-browse"
|
||||
0
|
||||
(marionette-eval
|
||||
'(system* "avahi-browse" "-avt")
|
||||
marionette))
|
||||
|
||||
(test-assert "gethostbyname .local"
|
||||
(match (pk 'gethostbyname
|
||||
(marionette-eval '(gethostbyname #$mdns-host-name)
|
||||
marionette))
|
||||
((? vector? result)
|
||||
(and (string=? (hostent:name result) #$mdns-host-name)
|
||||
(= (hostent:addrtype result) AF_INET)))))
|
||||
(test-assert "getaddrinfo .local"
|
||||
;; Wait for the 'avahi-daemon' service and perform a resolution.
|
||||
(match (marionette-eval
|
||||
'(getaddrinfo #$mdns-host-name)
|
||||
marionette)
|
||||
(((? vector? addrinfos) ..1)
|
||||
(pk 'getaddrinfo addrinfos)
|
||||
(and (any (lambda (ai)
|
||||
(= AF_INET (addrinfo:fam ai)))
|
||||
addrinfos)
|
||||
(any (lambda (ai)
|
||||
(= AF_INET6 (addrinfo:fam ai)))
|
||||
addrinfos)))))
|
||||
|
||||
(test-assert "gethostbyname .local"
|
||||
(match (pk 'gethostbyname
|
||||
(marionette-eval '(gethostbyname #$mdns-host-name)
|
||||
marionette))
|
||||
((? vector? result)
|
||||
(and (string=? (hostent:name result) #$mdns-host-name)
|
||||
(= (hostent:addrtype result) AF_INET)))))
|
||||
|
||||
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
|
||||
(gexp->derivation "nss-mdns" test)))
|
||||
(gexp->derivation "nss-mdns" test))
|
||||
|
||||
(define %test-nss-mdns
|
||||
(system-test
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#:use-module (gnu packages wordnet)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix store)
|
||||
#:use-module (guix monads)
|
||||
#:use-module (guix packages)
|
||||
#:use-module (guix modules)
|
||||
#:export (%test-dicod))
|
||||
|
@ -54,86 +53,90 @@
|
|||
|
||||
(define* (run-dicod-test)
|
||||
"Run tests of 'dicod-service-type'."
|
||||
(mlet* %store-monad ((os -> (marionette-operating-system
|
||||
%dicod-os
|
||||
#:imported-modules
|
||||
(source-module-closure '((gnu services herd)))))
|
||||
(command (system-qemu-image/shared-store-script
|
||||
os #:graphic? #f)))
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (ice-9 rdelim)
|
||||
(ice-9 regex)
|
||||
(srfi srfi-64)
|
||||
(gnu build marionette))
|
||||
(define marionette
|
||||
;; Forward the guest's DICT port to local port 8000.
|
||||
(make-marionette (list #$command "-net"
|
||||
"user,hostfwd=tcp::8000-:2628")))
|
||||
(define os
|
||||
(marionette-operating-system
|
||||
%dicod-os
|
||||
#:imported-modules
|
||||
(source-module-closure '((gnu services herd)))))
|
||||
|
||||
(define %dico-socket
|
||||
(socket PF_INET SOCK_STREAM 0))
|
||||
(define vm
|
||||
(virtual-machine
|
||||
(operating-system os)
|
||||
(port-forwardings '((8000 . 2628)))))
|
||||
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (ice-9 rdelim)
|
||||
(ice-9 regex)
|
||||
(srfi srfi-64)
|
||||
(gnu build marionette))
|
||||
(define marionette
|
||||
;; Forward the guest's DICT port to local port 8000.
|
||||
(make-marionette (list #$vm)))
|
||||
|
||||
(test-begin "dicod")
|
||||
(define %dico-socket
|
||||
(socket PF_INET SOCK_STREAM 0))
|
||||
|
||||
;; Wait for the service to be started.
|
||||
(test-eq "service is running"
|
||||
'running!
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'dicod)
|
||||
'running!)
|
||||
marionette))
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
|
||||
;; Wait until dicod is actually listening.
|
||||
;; TODO: Use a PID file instead.
|
||||
(test-assert "connect inside"
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (ice-9 rdelim))
|
||||
(let ((sock (socket PF_INET SOCK_STREAM 0)))
|
||||
(let loop ((i 0))
|
||||
(pk 'try i)
|
||||
(catch 'system-error
|
||||
(lambda ()
|
||||
(connect sock AF_INET INADDR_LOOPBACK 2628))
|
||||
(lambda args
|
||||
(pk 'connection-error args)
|
||||
(when (< i 20)
|
||||
(sleep 1)
|
||||
(loop (+ 1 i))))))
|
||||
(read-line sock 'concat)))
|
||||
marionette))
|
||||
(test-begin "dicod")
|
||||
|
||||
(test-assert "connect"
|
||||
(let ((addr (make-socket-address AF_INET INADDR_LOOPBACK 8000)))
|
||||
(connect %dico-socket addr)
|
||||
(read-line %dico-socket 'concat)))
|
||||
;; Wait for the service to be started.
|
||||
(test-eq "service is running"
|
||||
'running!
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'dicod)
|
||||
'running!)
|
||||
marionette))
|
||||
|
||||
(test-equal "CLIENT"
|
||||
"250 ok\r\n"
|
||||
(begin
|
||||
(display "CLIENT \"GNU Guile\"\r\n" %dico-socket)
|
||||
(read-line %dico-socket 'concat)))
|
||||
;; Wait until dicod is actually listening.
|
||||
;; TODO: Use a PID file instead.
|
||||
(test-assert "connect inside"
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (ice-9 rdelim))
|
||||
(let ((sock (socket PF_INET SOCK_STREAM 0)))
|
||||
(let loop ((i 0))
|
||||
(pk 'try i)
|
||||
(catch 'system-error
|
||||
(lambda ()
|
||||
(connect sock AF_INET INADDR_LOOPBACK 2628))
|
||||
(lambda args
|
||||
(pk 'connection-error args)
|
||||
(when (< i 20)
|
||||
(sleep 1)
|
||||
(loop (+ 1 i))))))
|
||||
(read-line sock 'concat)))
|
||||
marionette))
|
||||
|
||||
(test-assert "DEFINE"
|
||||
(begin
|
||||
(display "DEFINE ! hello\r\n" %dico-socket)
|
||||
(display "QUIT\r\n" %dico-socket)
|
||||
(let ((result (read-string %dico-socket)))
|
||||
(and (string-contains result "gcide")
|
||||
(string-contains result "hello")
|
||||
result))))
|
||||
(test-assert "connect"
|
||||
(let ((addr (make-socket-address AF_INET INADDR_LOOPBACK 8000)))
|
||||
(connect %dico-socket addr)
|
||||
(read-line %dico-socket 'concat)))
|
||||
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
(test-equal "CLIENT"
|
||||
"250 ok\r\n"
|
||||
(begin
|
||||
(display "CLIENT \"GNU Guile\"\r\n" %dico-socket)
|
||||
(read-line %dico-socket 'concat)))
|
||||
|
||||
(gexp->derivation "dicod" test)))
|
||||
(test-assert "DEFINE"
|
||||
(begin
|
||||
(display "DEFINE ! hello\r\n" %dico-socket)
|
||||
(display "QUIT\r\n" %dico-socket)
|
||||
(let ((result (read-string %dico-socket)))
|
||||
(and (string-contains result "gcide")
|
||||
(string-contains result "hello")
|
||||
result))))
|
||||
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
|
||||
(gexp->derivation "dicod" test))
|
||||
|
||||
(define %test-dicod
|
||||
(system-test
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2016 Sou Bunnbu <iyzsong@member.fsf.org>
|
||||
;;; Copyright © 2017 Carlo Zancanaro <carlo@zancanaro.id.au>
|
||||
;;; Copyright © 2017 Ludovic Courtès <ludo@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
|
@ -25,7 +26,6 @@
|
|||
#:use-module (gnu services mail)
|
||||
#:use-module (gnu services networking)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix monads)
|
||||
#:use-module (guix store)
|
||||
#:use-module (ice-9 ftw)
|
||||
#:export (%test-opensmtpd
|
||||
|
@ -44,105 +44,105 @@ accept from any for local deliver to mbox
|
|||
|
||||
(define (run-opensmtpd-test)
|
||||
"Return a test of an OS running OpenSMTPD service."
|
||||
(mlet* %store-monad ((command (system-qemu-image/shared-store-script
|
||||
(marionette-operating-system
|
||||
%opensmtpd-os
|
||||
#:imported-modules '((gnu services herd)))
|
||||
#:graphic? #f)))
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (rnrs base)
|
||||
(srfi srfi-64)
|
||||
(ice-9 rdelim)
|
||||
(ice-9 regex)
|
||||
(gnu build marionette))
|
||||
(define vm
|
||||
(virtual-machine
|
||||
(operating-system (marionette-operating-system
|
||||
%opensmtpd-os
|
||||
#:imported-modules '((gnu services herd))))
|
||||
(port-forwardings '((1025 . 25)))))
|
||||
|
||||
(define marionette
|
||||
(make-marionette
|
||||
;; Enable TCP forwarding of the guest's port 25.
|
||||
'(#$command "-net" "user,hostfwd=tcp::1025-:25")))
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (rnrs base)
|
||||
(srfi srfi-64)
|
||||
(ice-9 rdelim)
|
||||
(ice-9 regex)
|
||||
(gnu build marionette))
|
||||
|
||||
(define (read-reply-code port)
|
||||
"Read a SMTP reply from PORT and return its reply code."
|
||||
(let* ((line (read-line port))
|
||||
(mo (string-match "([0-9]+)([ -]).*" line))
|
||||
(code (string->number (match:substring mo 1)))
|
||||
(finished? (string= " " (match:substring mo 2))))
|
||||
(if finished?
|
||||
code
|
||||
(read-reply-code port))))
|
||||
(define marionette
|
||||
(make-marionette '(#$vm)))
|
||||
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
(define (read-reply-code port)
|
||||
"Read a SMTP reply from PORT and return its reply code."
|
||||
(let* ((line (read-line port))
|
||||
(mo (string-match "([0-9]+)([ -]).*" line))
|
||||
(code (string->number (match:substring mo 1)))
|
||||
(finished? (string= " " (match:substring mo 2))))
|
||||
(if finished?
|
||||
code
|
||||
(read-reply-code port))))
|
||||
|
||||
(test-begin "opensmptd")
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
|
||||
(test-assert "service is running"
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'smtpd)
|
||||
#t)
|
||||
marionette))
|
||||
(test-begin "opensmptd")
|
||||
|
||||
(test-assert "mbox is empty"
|
||||
(marionette-eval
|
||||
'(and (file-exists? "/var/mail")
|
||||
(not (file-exists? "/var/mail/root")))
|
||||
marionette))
|
||||
(test-assert "service is running"
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'smtpd)
|
||||
#t)
|
||||
marionette))
|
||||
|
||||
(test-eq "accept an email"
|
||||
#t
|
||||
(let* ((smtp (socket AF_INET SOCK_STREAM 0))
|
||||
(addr (make-socket-address AF_INET INADDR_LOOPBACK 1025)))
|
||||
(connect smtp addr)
|
||||
;; Be greeted.
|
||||
(read-reply-code smtp) ;220
|
||||
;; Greet the server.
|
||||
(write-line "EHLO somehost" smtp)
|
||||
(read-reply-code smtp) ;250
|
||||
;; Set sender email.
|
||||
(write-line "MAIL FROM: <someone>" smtp)
|
||||
(read-reply-code smtp) ;250
|
||||
;; Set recipient email.
|
||||
(write-line "RCPT TO: <root>" smtp)
|
||||
(read-reply-code smtp) ;250
|
||||
;; Send message.
|
||||
(write-line "DATA" smtp)
|
||||
(read-reply-code smtp) ;354
|
||||
(write-line "Subject: Hello" smtp)
|
||||
(newline smtp)
|
||||
(write-line "Nice to meet you!" smtp)
|
||||
(write-line "." smtp)
|
||||
(read-reply-code smtp) ;250
|
||||
;; Say goodbye.
|
||||
(write-line "QUIT" smtp)
|
||||
(read-reply-code smtp) ;221
|
||||
(close smtp)
|
||||
#t))
|
||||
(test-assert "mbox is empty"
|
||||
(marionette-eval
|
||||
'(and (file-exists? "/var/mail")
|
||||
(not (file-exists? "/var/mail/root")))
|
||||
marionette))
|
||||
|
||||
(test-assert "mail arrived"
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (ice-9 popen)
|
||||
(ice-9 rdelim))
|
||||
(test-eq "accept an email"
|
||||
#t
|
||||
(let* ((smtp (socket AF_INET SOCK_STREAM 0))
|
||||
(addr (make-socket-address AF_INET INADDR_LOOPBACK 1025)))
|
||||
(connect smtp addr)
|
||||
;; Be greeted.
|
||||
(read-reply-code smtp) ;220
|
||||
;; Greet the server.
|
||||
(write-line "EHLO somehost" smtp)
|
||||
(read-reply-code smtp) ;250
|
||||
;; Set sender email.
|
||||
(write-line "MAIL FROM: <someone>" smtp)
|
||||
(read-reply-code smtp) ;250
|
||||
;; Set recipient email.
|
||||
(write-line "RCPT TO: <root>" smtp)
|
||||
(read-reply-code smtp) ;250
|
||||
;; Send message.
|
||||
(write-line "DATA" smtp)
|
||||
(read-reply-code smtp) ;354
|
||||
(write-line "Subject: Hello" smtp)
|
||||
(newline smtp)
|
||||
(write-line "Nice to meet you!" smtp)
|
||||
(write-line "." smtp)
|
||||
(read-reply-code smtp) ;250
|
||||
;; Say goodbye.
|
||||
(write-line "QUIT" smtp)
|
||||
(read-reply-code smtp) ;221
|
||||
(close smtp)
|
||||
#t))
|
||||
|
||||
(define (queue-empty?)
|
||||
(eof-object?
|
||||
(read-line
|
||||
(open-input-pipe "smtpctl show queue"))))
|
||||
(test-assert "mail arrived"
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (ice-9 popen)
|
||||
(ice-9 rdelim))
|
||||
|
||||
(let wait ()
|
||||
(if (queue-empty?)
|
||||
(file-exists? "/var/mail/root")
|
||||
(begin (sleep 1) (wait)))))
|
||||
marionette))
|
||||
(define (queue-empty?)
|
||||
(eof-object?
|
||||
(read-line
|
||||
(open-input-pipe "smtpctl show queue"))))
|
||||
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
(let wait ()
|
||||
(if (queue-empty?)
|
||||
(file-exists? "/var/mail/root")
|
||||
(begin (sleep 1) (wait)))))
|
||||
marionette))
|
||||
|
||||
(gexp->derivation "opensmtpd-test" test)))
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
|
||||
(gexp->derivation "opensmtpd-test" test))
|
||||
|
||||
(define %test-opensmtpd
|
||||
(system-test
|
||||
|
@ -179,100 +179,100 @@ acl_check_data:
|
|||
|
||||
(define (run-exim-test)
|
||||
"Return a test of an OS running an Exim service."
|
||||
(mlet* %store-monad ((command (system-qemu-image/shared-store-script
|
||||
(marionette-operating-system
|
||||
%exim-os
|
||||
#:imported-modules '((gnu services herd)))
|
||||
#:graphic? #f)))
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette)
|
||||
(ice-9 ftw))
|
||||
#~(begin
|
||||
(use-modules (rnrs base)
|
||||
(srfi srfi-64)
|
||||
(ice-9 ftw)
|
||||
(ice-9 rdelim)
|
||||
(ice-9 regex)
|
||||
(gnu build marionette))
|
||||
(define vm
|
||||
(virtual-machine
|
||||
(operating-system (marionette-operating-system
|
||||
%exim-os
|
||||
#:imported-modules '((gnu services herd))))
|
||||
(port-forwardings '((1025 . 25)))))
|
||||
|
||||
(define marionette
|
||||
(make-marionette
|
||||
;; Enable TCP forwarding of the guest's port 25.
|
||||
'(#$command "-net" "user,hostfwd=tcp::1025-:25")))
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette)
|
||||
(ice-9 ftw))
|
||||
#~(begin
|
||||
(use-modules (rnrs base)
|
||||
(srfi srfi-64)
|
||||
(ice-9 ftw)
|
||||
(ice-9 rdelim)
|
||||
(ice-9 regex)
|
||||
(gnu build marionette))
|
||||
|
||||
(define (read-reply-code port)
|
||||
"Read a SMTP reply from PORT and return its reply code."
|
||||
(let* ((line (read-line port))
|
||||
(mo (string-match "([0-9]+)([ -]).*" line))
|
||||
(code (string->number (match:substring mo 1)))
|
||||
(finished? (string= " " (match:substring mo 2))))
|
||||
(if finished?
|
||||
code
|
||||
(read-reply-code port))))
|
||||
(define marionette
|
||||
(make-marionette '(#$vm)))
|
||||
|
||||
(define smtp (socket AF_INET SOCK_STREAM 0))
|
||||
(define addr (make-socket-address AF_INET INADDR_LOOPBACK 1025))
|
||||
(define (read-reply-code port)
|
||||
"Read a SMTP reply from PORT and return its reply code."
|
||||
(let* ((line (read-line port))
|
||||
(mo (string-match "([0-9]+)([ -]).*" line))
|
||||
(code (string->number (match:substring mo 1)))
|
||||
(finished? (string= " " (match:substring mo 2))))
|
||||
(if finished?
|
||||
code
|
||||
(read-reply-code port))))
|
||||
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
(define smtp (socket AF_INET SOCK_STREAM 0))
|
||||
(define addr (make-socket-address AF_INET INADDR_LOOPBACK 1025))
|
||||
|
||||
(test-begin "exim")
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
|
||||
(test-assert "service is running"
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'exim)
|
||||
#t)
|
||||
marionette))
|
||||
(test-begin "exim")
|
||||
|
||||
(sleep 1) ;; give the service time to start talking
|
||||
(test-assert "service is running"
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'exim)
|
||||
#t)
|
||||
marionette))
|
||||
|
||||
(connect smtp addr)
|
||||
;; Be greeted.
|
||||
(test-eq "greeting received"
|
||||
220 (read-reply-code smtp))
|
||||
;; Greet the server.
|
||||
(write-line "EHLO somehost" smtp)
|
||||
(test-eq "greeting successful"
|
||||
250 (read-reply-code smtp))
|
||||
;; Set sender email.
|
||||
(write-line "MAIL FROM: test@example.com" smtp)
|
||||
(test-eq "sender set"
|
||||
250 (read-reply-code smtp)) ;250
|
||||
;; Set recipient email.
|
||||
(write-line "RCPT TO: root@komputilo" smtp)
|
||||
(test-eq "recipient set"
|
||||
250 (read-reply-code smtp)) ;250
|
||||
;; Send message.
|
||||
(write-line "DATA" smtp)
|
||||
(test-eq "data begun"
|
||||
354 (read-reply-code smtp)) ;354
|
||||
(write-line "Subject: Hello" smtp)
|
||||
(newline smtp)
|
||||
(write-line "Nice to meet you!" smtp)
|
||||
(write-line "." smtp)
|
||||
(test-eq "message sent"
|
||||
250 (read-reply-code smtp)) ;250
|
||||
;; Say goodbye.
|
||||
(write-line "QUIT" smtp)
|
||||
(test-eq "quit successful"
|
||||
221 (read-reply-code smtp)) ;221
|
||||
(close smtp)
|
||||
(sleep 1) ;; give the service time to start talking
|
||||
|
||||
(test-eq "the email is received"
|
||||
1
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (ice-9 ftw))
|
||||
(length (scandir "/var/spool/exim/msglog"
|
||||
(lambda (x) (not (string-prefix? "." x))))))
|
||||
marionette))
|
||||
(connect smtp addr)
|
||||
;; Be greeted.
|
||||
(test-eq "greeting received"
|
||||
220 (read-reply-code smtp))
|
||||
;; Greet the server.
|
||||
(write-line "EHLO somehost" smtp)
|
||||
(test-eq "greeting successful"
|
||||
250 (read-reply-code smtp))
|
||||
;; Set sender email.
|
||||
(write-line "MAIL FROM: test@example.com" smtp)
|
||||
(test-eq "sender set"
|
||||
250 (read-reply-code smtp)) ;250
|
||||
;; Set recipient email.
|
||||
(write-line "RCPT TO: root@komputilo" smtp)
|
||||
(test-eq "recipient set"
|
||||
250 (read-reply-code smtp)) ;250
|
||||
;; Send message.
|
||||
(write-line "DATA" smtp)
|
||||
(test-eq "data begun"
|
||||
354 (read-reply-code smtp)) ;354
|
||||
(write-line "Subject: Hello" smtp)
|
||||
(newline smtp)
|
||||
(write-line "Nice to meet you!" smtp)
|
||||
(write-line "." smtp)
|
||||
(test-eq "message sent"
|
||||
250 (read-reply-code smtp)) ;250
|
||||
;; Say goodbye.
|
||||
(write-line "QUIT" smtp)
|
||||
(test-eq "quit successful"
|
||||
221 (read-reply-code smtp)) ;221
|
||||
(close smtp)
|
||||
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
(test-eq "the email is received"
|
||||
1
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (ice-9 ftw))
|
||||
(length (scandir "/var/spool/exim/msglog"
|
||||
(lambda (x) (not (string-prefix? "." x))))))
|
||||
marionette))
|
||||
|
||||
(gexp->derivation "exim-test" test)))
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
|
||||
(gexp->derivation "exim-test" test))
|
||||
|
||||
(define %test-exim
|
||||
(system-test
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org>
|
||||
;;; Copyright © 2017 Ludovic Courtès <ludo@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
|
@ -26,108 +27,109 @@
|
|||
#:use-module (gnu packages messaging)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix store)
|
||||
#:use-module (guix monads)
|
||||
#:export (%test-prosody))
|
||||
|
||||
(define (run-xmpp-test name xmpp-service pid-file create-account)
|
||||
"Run a test of an OS running XMPP-SERVICE, which writes its PID to PID-FILE."
|
||||
(mlet* %store-monad ((os -> (marionette-operating-system
|
||||
(simple-operating-system (dhcp-client-service)
|
||||
xmpp-service)
|
||||
#:imported-modules '((gnu services herd))))
|
||||
(command (system-qemu-image/shared-store-script
|
||||
os #:graphic? #f))
|
||||
(username -> "alice")
|
||||
(server -> "localhost")
|
||||
(jid -> (string-append username "@" server))
|
||||
(password -> "correct horse battery staple")
|
||||
(port -> 15222)
|
||||
(message -> "hello world")
|
||||
(witness -> "/tmp/freetalk-witness"))
|
||||
(define os
|
||||
(marionette-operating-system
|
||||
(simple-operating-system (dhcp-client-service)
|
||||
xmpp-service)
|
||||
#:imported-modules '((gnu services herd))))
|
||||
|
||||
(define script.ft
|
||||
(scheme-file
|
||||
"script.ft"
|
||||
#~(begin
|
||||
(define (handle-received-message time from nickname message)
|
||||
(define (touch file-name)
|
||||
(call-with-output-file file-name (const #t)))
|
||||
(when (equal? message #$message)
|
||||
(touch #$witness)))
|
||||
(add-hook! ft-message-receive-hook handle-received-message)
|
||||
(define port 15222)
|
||||
|
||||
(ft-set-jid! #$jid)
|
||||
(ft-set-password! #$password)
|
||||
(ft-set-server! #$server)
|
||||
(ft-set-port! #$port)
|
||||
(ft-set-sslconn! #f)
|
||||
(ft-connect-blocking)
|
||||
(ft-send-message #$jid #$message)
|
||||
(define vm
|
||||
(virtual-machine
|
||||
(operating-system os)
|
||||
(port-forwardings `((,port . 5222)))))
|
||||
|
||||
(ft-set-daemon)
|
||||
(ft-main-loop))))
|
||||
(define username "alice")
|
||||
(define server "localhost")
|
||||
(define jid (string-append username "@" server))
|
||||
(define password "correct horse battery staple")
|
||||
(define message "hello world")
|
||||
(define witness "/tmp/freetalk-witness")
|
||||
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (gnu build marionette)
|
||||
(srfi srfi-64))
|
||||
(define script.ft
|
||||
(scheme-file
|
||||
"script.ft"
|
||||
#~(begin
|
||||
(define (handle-received-message time from nickname message)
|
||||
(define (touch file-name)
|
||||
(call-with-output-file file-name (const #t)))
|
||||
(when (equal? message #$message)
|
||||
(touch #$witness)))
|
||||
(add-hook! ft-message-receive-hook handle-received-message)
|
||||
|
||||
(define marionette
|
||||
;; Enable TCP forwarding of the guest's port 5222.
|
||||
(make-marionette (list #$command "-net"
|
||||
(string-append "user,hostfwd=tcp::"
|
||||
(number->string #$port)
|
||||
"-:5222"))))
|
||||
(ft-set-jid! #$jid)
|
||||
(ft-set-password! #$password)
|
||||
(ft-set-server! #$server)
|
||||
(ft-set-port! #$port)
|
||||
(ft-set-sslconn! #f)
|
||||
(ft-connect-blocking)
|
||||
(ft-send-message #$jid #$message)
|
||||
|
||||
(define (host-wait-for-file file)
|
||||
;; Wait until FILE exists in the host.
|
||||
(let loop ((i 60))
|
||||
(cond ((file-exists? file)
|
||||
#t)
|
||||
((> i 0)
|
||||
(begin
|
||||
(sleep 1))
|
||||
(loop (- i 1)))
|
||||
(else
|
||||
(error "file didn't show up" file)))))
|
||||
(ft-set-daemon)
|
||||
(ft-main-loop))))
|
||||
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (gnu build marionette)
|
||||
(srfi srfi-64))
|
||||
|
||||
(test-begin "xmpp")
|
||||
(define marionette
|
||||
(make-marionette (list #$vm)))
|
||||
|
||||
;; Wait for XMPP service to be up and running.
|
||||
(test-eq "service running"
|
||||
'running!
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'xmpp-daemon)
|
||||
'running!)
|
||||
marionette))
|
||||
(define (host-wait-for-file file)
|
||||
;; Wait until FILE exists in the host.
|
||||
(let loop ((i 60))
|
||||
(cond ((file-exists? file)
|
||||
#t)
|
||||
((> i 0)
|
||||
(begin
|
||||
(sleep 1))
|
||||
(loop (- i 1)))
|
||||
(else
|
||||
(error "file didn't show up" file)))))
|
||||
|
||||
;; Check XMPP service's PID.
|
||||
(test-assert "service process id"
|
||||
(let ((pid (number->string (wait-for-file #$pid-file
|
||||
marionette))))
|
||||
(marionette-eval `(file-exists? (string-append "/proc/" ,pid))
|
||||
marionette)))
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
|
||||
;; Alice sends an XMPP message to herself, with Freetalk.
|
||||
(test-assert "client-to-server communication"
|
||||
(let ((freetalk-bin (string-append #$freetalk "/bin/freetalk")))
|
||||
(marionette-eval '(system* #$create-account #$jid #$password)
|
||||
marionette)
|
||||
;; Freetalk requires write access to $HOME.
|
||||
(setenv "HOME" "/tmp")
|
||||
(system* freetalk-bin "-s" #$script.ft)
|
||||
(host-wait-for-file #$witness)))
|
||||
(test-begin "xmpp")
|
||||
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
;; Wait for XMPP service to be up and running.
|
||||
(test-eq "service running"
|
||||
'running!
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'xmpp-daemon)
|
||||
'running!)
|
||||
marionette))
|
||||
|
||||
(gexp->derivation name test)))
|
||||
;; Check XMPP service's PID.
|
||||
(test-assert "service process id"
|
||||
(let ((pid (number->string (wait-for-file #$pid-file
|
||||
marionette))))
|
||||
(marionette-eval `(file-exists? (string-append "/proc/" ,pid))
|
||||
marionette)))
|
||||
|
||||
;; Alice sends an XMPP message to herself, with Freetalk.
|
||||
(test-assert "client-to-server communication"
|
||||
(let ((freetalk-bin (string-append #$freetalk "/bin/freetalk")))
|
||||
(marionette-eval '(system* #$create-account #$jid #$password)
|
||||
marionette)
|
||||
;; Freetalk requires write access to $HOME.
|
||||
(setenv "HOME" "/tmp")
|
||||
(system* freetalk-bin "-s" #$script.ft)
|
||||
(host-wait-for-file #$witness)))
|
||||
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
|
||||
(gexp->derivation name test))
|
||||
|
||||
(define %create-prosody-account
|
||||
(program-file
|
||||
|
|
|
@ -74,60 +74,61 @@ done" ))))))))))
|
|||
(define* (run-inetd-test)
|
||||
"Run tests in %INETD-OS, where the inetd service provides an echo service on
|
||||
port 7, and a dict service on port 2628."
|
||||
(mlet* %store-monad ((os -> (marionette-operating-system %inetd-os))
|
||||
(command (system-qemu-image/shared-store-script
|
||||
os #:graphic? #f)))
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (ice-9 rdelim)
|
||||
(srfi srfi-64)
|
||||
(gnu build marionette))
|
||||
(define marionette
|
||||
;; Forward guest ports 7 and 2628 to host ports 8007 and 8628.
|
||||
(make-marionette (list #$command "-net"
|
||||
(string-append
|
||||
"user"
|
||||
",hostfwd=tcp::8007-:7"
|
||||
",hostfwd=tcp::8628-:2628"))))
|
||||
(define os
|
||||
(marionette-operating-system %inetd-os))
|
||||
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
(define vm
|
||||
(virtual-machine
|
||||
(operating-system os)
|
||||
(port-forwardings `((8007 . 7)
|
||||
(8628 . 2628)))))
|
||||
|
||||
(test-begin "inetd")
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (ice-9 rdelim)
|
||||
(srfi srfi-64)
|
||||
(gnu build marionette))
|
||||
(define marionette
|
||||
(make-marionette (list #$vm)))
|
||||
|
||||
;; Make sure the PID file is created.
|
||||
(test-assert "PID file"
|
||||
(marionette-eval
|
||||
'(file-exists? "/var/run/inetd.pid")
|
||||
marionette))
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
|
||||
;; Test the echo service.
|
||||
(test-equal "echo response"
|
||||
"Hello, Guix!"
|
||||
(let ((echo (socket PF_INET SOCK_STREAM 0))
|
||||
(addr (make-socket-address AF_INET INADDR_LOOPBACK 8007)))
|
||||
(connect echo addr)
|
||||
(display "Hello, Guix!\n" echo)
|
||||
(let ((response (read-line echo)))
|
||||
(close echo)
|
||||
response)))
|
||||
(test-begin "inetd")
|
||||
|
||||
;; Test the dict service
|
||||
(test-equal "dict response"
|
||||
"GNU Guix is a package management tool for the GNU system."
|
||||
(let ((dict (socket PF_INET SOCK_STREAM 0))
|
||||
(addr (make-socket-address AF_INET INADDR_LOOPBACK 8628)))
|
||||
(connect dict addr)
|
||||
(display "DEFINE Guix\n" dict)
|
||||
(let ((response (read-line dict)))
|
||||
(close dict)
|
||||
response)))
|
||||
;; Make sure the PID file is created.
|
||||
(test-assert "PID file"
|
||||
(marionette-eval
|
||||
'(file-exists? "/var/run/inetd.pid")
|
||||
marionette))
|
||||
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
;; Test the echo service.
|
||||
(test-equal "echo response"
|
||||
"Hello, Guix!"
|
||||
(let ((echo (socket PF_INET SOCK_STREAM 0))
|
||||
(addr (make-socket-address AF_INET INADDR_LOOPBACK 8007)))
|
||||
(connect echo addr)
|
||||
(display "Hello, Guix!\n" echo)
|
||||
(let ((response (read-line echo)))
|
||||
(close echo)
|
||||
response)))
|
||||
|
||||
(gexp->derivation "inetd-test" test)))
|
||||
;; Test the dict service
|
||||
(test-equal "dict response"
|
||||
"GNU Guix is a package management tool for the GNU system."
|
||||
(let ((dict (socket PF_INET SOCK_STREAM 0))
|
||||
(addr (make-socket-address AF_INET INADDR_LOOPBACK 8628)))
|
||||
(connect dict addr)
|
||||
(display "DEFINE Guix\n" dict)
|
||||
(let ((response (read-line dict)))
|
||||
(close dict)
|
||||
response)))
|
||||
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
|
||||
(gexp->derivation "inetd-test" test))
|
||||
|
||||
(define %test-inetd
|
||||
(system-test
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2016 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2016, 2017 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2016 John Darrington <jmd@gnu.org>
|
||||
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
|
||||
;;;
|
||||
|
@ -55,75 +55,75 @@
|
|||
|
||||
(define (run-nfs-test name socket)
|
||||
"Run a test of an OS running RPC-SERVICE, which should create SOCKET."
|
||||
(mlet* %store-monad ((os -> (marionette-operating-system
|
||||
%base-os
|
||||
#:imported-modules '((gnu services herd)
|
||||
(guix combinators))))
|
||||
(command (system-qemu-image/shared-store-script
|
||||
os #:graphic? #f)))
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (gnu build marionette)
|
||||
(srfi srfi-64))
|
||||
(define os
|
||||
(marionette-operating-system
|
||||
%base-os
|
||||
#:imported-modules '((gnu services herd)
|
||||
(guix combinators))))
|
||||
|
||||
(define marionette
|
||||
(make-marionette (list #$command)))
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (gnu build marionette)
|
||||
(srfi srfi-64))
|
||||
|
||||
(define (wait-for-socket file)
|
||||
;; Wait until SOCKET exists in the guest
|
||||
(marionette-eval
|
||||
`(let loop ((i 10))
|
||||
(cond ((and (file-exists? ,file)
|
||||
(eq? 'socket (stat:type (stat ,file))))
|
||||
#t)
|
||||
((> i 0)
|
||||
(sleep 1)
|
||||
(loop (- i 1)))
|
||||
(else
|
||||
(error "Socket didn't show up: " ,file))))
|
||||
marionette))
|
||||
(define marionette
|
||||
(make-marionette (list #$(virtual-machine os))))
|
||||
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
(define (wait-for-socket file)
|
||||
;; Wait until SOCKET exists in the guest
|
||||
(marionette-eval
|
||||
`(let loop ((i 10))
|
||||
(cond ((and (file-exists? ,file)
|
||||
(eq? 'socket (stat:type (stat ,file))))
|
||||
#t)
|
||||
((> i 0)
|
||||
(sleep 1)
|
||||
(loop (- i 1)))
|
||||
(else
|
||||
(error "Socket didn't show up: " ,file))))
|
||||
marionette))
|
||||
|
||||
(test-begin "rpc-daemon")
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
|
||||
;; Wait for the rpcbind daemon to be up and running.
|
||||
(test-eq "RPC service running"
|
||||
'running!
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'rpcbind-daemon)
|
||||
'running!)
|
||||
marionette))
|
||||
(test-begin "rpc-daemon")
|
||||
|
||||
;; Check the socket file and that the service is still running.
|
||||
(test-assert "RPC socket exists"
|
||||
(and
|
||||
(wait-for-socket #$socket)
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd)
|
||||
(srfi srfi-1))
|
||||
;; Wait for the rpcbind daemon to be up and running.
|
||||
(test-eq "RPC service running"
|
||||
'running!
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'rpcbind-daemon)
|
||||
'running!)
|
||||
marionette))
|
||||
|
||||
(live-service-running
|
||||
(find (lambda (live)
|
||||
(memq 'rpcbind-daemon
|
||||
(live-service-provision live)))
|
||||
(current-services))))
|
||||
marionette)))
|
||||
;; Check the socket file and that the service is still running.
|
||||
(test-assert "RPC socket exists"
|
||||
(and
|
||||
(wait-for-socket #$socket)
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd)
|
||||
(srfi srfi-1))
|
||||
|
||||
(test-assert "Probe RPC daemon"
|
||||
(marionette-eval
|
||||
'(zero? (system* "rpcinfo" "-p"))
|
||||
marionette))
|
||||
(live-service-running
|
||||
(find (lambda (live)
|
||||
(memq 'rpcbind-daemon
|
||||
(live-service-provision live)))
|
||||
(current-services))))
|
||||
marionette)))
|
||||
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
(test-assert "Probe RPC daemon"
|
||||
(marionette-eval
|
||||
'(zero? (system* "rpcinfo" "-p"))
|
||||
marionette))
|
||||
|
||||
(gexp->derivation name test)))
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
|
||||
(gexp->derivation name test))
|
||||
|
||||
(define %test-nfs
|
||||
(system-test
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#:use-module (gnu packages ssh)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix store)
|
||||
#:use-module (guix monads)
|
||||
#:export (%test-openssh
|
||||
%test-dropbear))
|
||||
|
||||
|
@ -37,142 +36,143 @@ SSH-SERVICE must be configured to listen on port 22 and to allow for root and
|
|||
empty-password logins.
|
||||
|
||||
When SFTP? is true, run an SFTP server test."
|
||||
(mlet* %store-monad ((os -> (marionette-operating-system
|
||||
(simple-operating-system
|
||||
(dhcp-client-service)
|
||||
ssh-service)
|
||||
#:imported-modules '((gnu services herd)
|
||||
(guix combinators))))
|
||||
(command (system-qemu-image/shared-store-script
|
||||
os #:graphic? #f)))
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(eval-when (expand load eval)
|
||||
;; Prepare to use Guile-SSH.
|
||||
(set! %load-path
|
||||
(cons (string-append #+guile2.0-ssh "/share/guile/site/"
|
||||
(effective-version))
|
||||
%load-path)))
|
||||
(define os
|
||||
(marionette-operating-system
|
||||
(simple-operating-system (dhcp-client-service) ssh-service)
|
||||
#:imported-modules '((gnu services herd)
|
||||
(guix combinators))))
|
||||
(define vm
|
||||
(virtual-machine
|
||||
(operating-system os)
|
||||
(port-forwardings '((2222 . 22)))))
|
||||
|
||||
(use-modules (gnu build marionette)
|
||||
(srfi srfi-26)
|
||||
(srfi srfi-64)
|
||||
(ice-9 match)
|
||||
(ssh session)
|
||||
(ssh auth)
|
||||
(ssh channel)
|
||||
(ssh sftp))
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(eval-when (expand load eval)
|
||||
;; Prepare to use Guile-SSH.
|
||||
(set! %load-path
|
||||
(cons (string-append #+guile2.0-ssh "/share/guile/site/"
|
||||
(effective-version))
|
||||
%load-path)))
|
||||
|
||||
(define marionette
|
||||
;; Enable TCP forwarding of the guest's port 22.
|
||||
(make-marionette (list #$command "-net"
|
||||
"user,hostfwd=tcp::2222-:22")))
|
||||
(use-modules (gnu build marionette)
|
||||
(srfi srfi-26)
|
||||
(srfi srfi-64)
|
||||
(ice-9 match)
|
||||
(ssh session)
|
||||
(ssh auth)
|
||||
(ssh channel)
|
||||
(ssh sftp))
|
||||
|
||||
(define (make-session-for-test)
|
||||
"Make a session with predefined parameters for a test."
|
||||
(make-session #:user "root"
|
||||
#:port 2222
|
||||
#:host "localhost"
|
||||
#:log-verbosity 'protocol))
|
||||
(define marionette
|
||||
;; Enable TCP forwarding of the guest's port 22.
|
||||
(make-marionette (list #$vm)))
|
||||
|
||||
(define (call-with-connected-session proc)
|
||||
"Call the one-argument procedure PROC with a freshly created and
|
||||
(define (make-session-for-test)
|
||||
"Make a session with predefined parameters for a test."
|
||||
(make-session #:user "root"
|
||||
#:port 2222
|
||||
#:host "localhost"
|
||||
#:log-verbosity 'protocol))
|
||||
|
||||
(define (call-with-connected-session proc)
|
||||
"Call the one-argument procedure PROC with a freshly created and
|
||||
connected SSH session object, return the result of the procedure call. The
|
||||
session is disconnected when the PROC is finished."
|
||||
(let ((session (make-session-for-test)))
|
||||
(dynamic-wind
|
||||
(lambda ()
|
||||
(let ((result (connect! session)))
|
||||
(unless (equal? result 'ok)
|
||||
(error "Could not connect to a server"
|
||||
session result))))
|
||||
(lambda () (proc session))
|
||||
(lambda () (disconnect! session)))))
|
||||
(let ((session (make-session-for-test)))
|
||||
(dynamic-wind
|
||||
(lambda ()
|
||||
(let ((result (connect! session)))
|
||||
(unless (equal? result 'ok)
|
||||
(error "Could not connect to a server"
|
||||
session result))))
|
||||
(lambda () (proc session))
|
||||
(lambda () (disconnect! session)))))
|
||||
|
||||
(define (call-with-connected-session/auth proc)
|
||||
"Make an authenticated session. We should be able to connect as
|
||||
(define (call-with-connected-session/auth proc)
|
||||
"Make an authenticated session. We should be able to connect as
|
||||
root with an empty password."
|
||||
(call-with-connected-session
|
||||
(lambda (session)
|
||||
;; Try the simple authentication methods. Dropbear requires
|
||||
;; 'none' when there are no passwords, whereas OpenSSH accepts
|
||||
;; 'password' with an empty password.
|
||||
(let loop ((methods (list (cut userauth-password! <> "")
|
||||
(cut userauth-none! <>))))
|
||||
(match methods
|
||||
(()
|
||||
(error "all the authentication methods failed"))
|
||||
((auth rest ...)
|
||||
(match (pk 'auth (auth session))
|
||||
('success
|
||||
(proc session))
|
||||
('denied
|
||||
(loop rest)))))))))
|
||||
(call-with-connected-session
|
||||
(lambda (session)
|
||||
;; Try the simple authentication methods. Dropbear requires
|
||||
;; 'none' when there are no passwords, whereas OpenSSH accepts
|
||||
;; 'password' with an empty password.
|
||||
(let loop ((methods (list (cut userauth-password! <> "")
|
||||
(cut userauth-none! <>))))
|
||||
(match methods
|
||||
(()
|
||||
(error "all the authentication methods failed"))
|
||||
((auth rest ...)
|
||||
(match (pk 'auth (auth session))
|
||||
('success
|
||||
(proc session))
|
||||
('denied
|
||||
(loop rest)))))))))
|
||||
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
|
||||
(test-begin "ssh-daemon")
|
||||
(test-begin "ssh-daemon")
|
||||
|
||||
;; Wait for sshd to be up and running.
|
||||
(test-eq "service running"
|
||||
'running!
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'ssh-daemon)
|
||||
'running!)
|
||||
marionette))
|
||||
;; Wait for sshd to be up and running.
|
||||
(test-eq "service running"
|
||||
'running!
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'ssh-daemon)
|
||||
'running!)
|
||||
marionette))
|
||||
|
||||
;; Check sshd's PID file.
|
||||
(test-equal "sshd PID"
|
||||
(wait-for-file #$pid-file marionette)
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd)
|
||||
(srfi srfi-1))
|
||||
;; Check sshd's PID file.
|
||||
(test-equal "sshd PID"
|
||||
(wait-for-file #$pid-file marionette)
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd)
|
||||
(srfi srfi-1))
|
||||
|
||||
(live-service-running
|
||||
(find (lambda (live)
|
||||
(memq 'ssh-daemon
|
||||
(live-service-provision live)))
|
||||
(current-services))))
|
||||
marionette))
|
||||
(live-service-running
|
||||
(find (lambda (live)
|
||||
(memq 'ssh-daemon
|
||||
(live-service-provision live)))
|
||||
(current-services))))
|
||||
marionette))
|
||||
|
||||
;; Connect to the guest over SSH. Make sure we can run a shell
|
||||
;; command there.
|
||||
(test-equal "shell command"
|
||||
'hello
|
||||
(call-with-connected-session/auth
|
||||
(lambda (session)
|
||||
;; FIXME: 'get-server-public-key' segfaults.
|
||||
;; (get-server-public-key session)
|
||||
(let ((channel (make-channel session)))
|
||||
(channel-open-session channel)
|
||||
(channel-request-exec channel "echo hello > /root/witness")
|
||||
(and (zero? (channel-get-exit-status channel))
|
||||
(wait-for-file "/root/witness" marionette))))))
|
||||
;; Connect to the guest over SSH. Make sure we can run a shell
|
||||
;; command there.
|
||||
(test-equal "shell command"
|
||||
'hello
|
||||
(call-with-connected-session/auth
|
||||
(lambda (session)
|
||||
;; FIXME: 'get-server-public-key' segfaults.
|
||||
;; (get-server-public-key session)
|
||||
(let ((channel (make-channel session)))
|
||||
(channel-open-session channel)
|
||||
(channel-request-exec channel "echo hello > /root/witness")
|
||||
(and (zero? (channel-get-exit-status channel))
|
||||
(wait-for-file "/root/witness" marionette))))))
|
||||
|
||||
;; Connect to the guest over SFTP. Make sure we can write and
|
||||
;; read a file there.
|
||||
(unless #$sftp?
|
||||
(test-skip 1))
|
||||
(test-equal "SFTP file writing and reading"
|
||||
'hello
|
||||
(call-with-connected-session/auth
|
||||
(lambda (session)
|
||||
(let ((sftp-session (make-sftp-session session))
|
||||
(witness "/root/sftp-witness"))
|
||||
(call-with-remote-output-file sftp-session witness
|
||||
(cut display "hello" <>))
|
||||
(call-with-remote-input-file sftp-session witness
|
||||
read)))))
|
||||
;; Connect to the guest over SFTP. Make sure we can write and
|
||||
;; read a file there.
|
||||
(unless #$sftp?
|
||||
(test-skip 1))
|
||||
(test-equal "SFTP file writing and reading"
|
||||
'hello
|
||||
(call-with-connected-session/auth
|
||||
(lambda (session)
|
||||
(let ((sftp-session (make-sftp-session session))
|
||||
(witness "/root/sftp-witness"))
|
||||
(call-with-remote-output-file sftp-session witness
|
||||
(cut display "hello" <>))
|
||||
(call-with-remote-input-file sftp-session witness
|
||||
read)))))
|
||||
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
|
||||
(gexp->derivation name test)))
|
||||
(gexp->derivation name test))
|
||||
|
||||
(define %test-openssh
|
||||
(system-test
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#:use-module (gnu services networking)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix store)
|
||||
#:use-module (guix monads)
|
||||
#:export (%test-nginx))
|
||||
|
||||
(define %index.html-contents
|
||||
|
@ -65,68 +64,68 @@
|
|||
(define* (run-nginx-test #:optional (http-port 8042))
|
||||
"Run tests in %NGINX-OS, which has nginx running and listening on
|
||||
HTTP-PORT."
|
||||
(mlet* %store-monad ((os -> (marionette-operating-system
|
||||
%nginx-os
|
||||
#:imported-modules '((gnu services herd)
|
||||
(guix combinators))))
|
||||
(command (system-qemu-image/shared-store-script
|
||||
os #:graphic? #f)))
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (srfi srfi-11) (srfi srfi-64)
|
||||
(gnu build marionette)
|
||||
(web uri)
|
||||
(web client)
|
||||
(web response))
|
||||
(define os
|
||||
(marionette-operating-system
|
||||
%nginx-os
|
||||
#:imported-modules '((gnu services herd)
|
||||
(guix combinators))))
|
||||
|
||||
(define marionette
|
||||
;; Forward the guest's HTTP-PORT, where nginx is listening, to
|
||||
;; port 8080 in the host.
|
||||
(make-marionette (list #$command "-net"
|
||||
(string-append
|
||||
"user,hostfwd=tcp::8080-:"
|
||||
#$(number->string http-port)))))
|
||||
(define vm
|
||||
(virtual-machine
|
||||
(operating-system os)
|
||||
(port-forwardings `((8080 . ,http-port)))))
|
||||
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (srfi srfi-11) (srfi srfi-64)
|
||||
(gnu build marionette)
|
||||
(web uri)
|
||||
(web client)
|
||||
(web response))
|
||||
|
||||
(test-begin "nginx")
|
||||
(define marionette
|
||||
(make-marionette (list #$vm)))
|
||||
|
||||
;; Wait for nginx to be up and running.
|
||||
(test-eq "service running"
|
||||
'running!
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'nginx)
|
||||
'running!)
|
||||
marionette))
|
||||
(mkdir #$output)
|
||||
(chdir #$output)
|
||||
|
||||
;; Make sure the PID file is created.
|
||||
(test-assert "PID file"
|
||||
(marionette-eval
|
||||
'(file-exists? "/var/run/nginx/pid")
|
||||
marionette))
|
||||
(test-begin "nginx")
|
||||
|
||||
;; Retrieve the index.html file we put in /srv.
|
||||
(test-equal "http-get"
|
||||
'(200 #$%index.html-contents)
|
||||
(let-values (((response text)
|
||||
(http-get "http://localhost:8080/index.html"
|
||||
#:decode-body? #t)))
|
||||
(list (response-code response) text)))
|
||||
;; Wait for nginx to be up and running.
|
||||
(test-eq "service running"
|
||||
'running!
|
||||
(marionette-eval
|
||||
'(begin
|
||||
(use-modules (gnu services herd))
|
||||
(start-service 'nginx)
|
||||
'running!)
|
||||
marionette))
|
||||
|
||||
;; There should be a log file in here.
|
||||
(test-assert "log file"
|
||||
(marionette-eval
|
||||
'(file-exists? "/var/log/nginx/access.log")
|
||||
marionette))
|
||||
;; Make sure the PID file is created.
|
||||
(test-assert "PID file"
|
||||
(marionette-eval
|
||||
'(file-exists? "/var/run/nginx/pid")
|
||||
marionette))
|
||||
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
;; Retrieve the index.html file we put in /srv.
|
||||
(test-equal "http-get"
|
||||
'(200 #$%index.html-contents)
|
||||
(let-values (((response text)
|
||||
(http-get "http://localhost:8080/index.html"
|
||||
#:decode-body? #t)))
|
||||
(list (response-code response) text)))
|
||||
|
||||
(gexp->derivation "nginx-test" test)))
|
||||
;; There should be a log file in here.
|
||||
(test-assert "log file"
|
||||
(marionette-eval
|
||||
'(file-exists? "/var/log/nginx/access.log")
|
||||
marionette))
|
||||
|
||||
(test-end)
|
||||
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
|
||||
|
||||
(gexp->derivation "nginx-test" test))
|
||||
|
||||
(define %test-nginx
|
||||
(system-test
|
||||
|
|
Reference in New Issue