1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2016 Sou Bunnbu <iyzsong@member.fsf.org>
3 ;;; Copyright © 2017 Carlo Zancanaro <carlo@zancanaro.id.au>
4 ;;; Copyright © 2017 Ludovic Courtès <ludo@gnu.org>
6 ;;; This file is part of GNU Guix.
8 ;;; GNU Guix is free software; you can redistribute it and/or modify it
9 ;;; under the terms of the GNU General Public License as published by
10 ;;; the Free Software Foundation; either version 3 of the License, or (at
11 ;;; your option) any later version.
13 ;;; GNU Guix is distributed in the hope that it will be useful, but
14 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;;; GNU General Public License for more details.
18 ;;; You should have received a copy of the GNU General Public License
19 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
21 (define-module (gnu tests mail)
22 #:use-module (gnu tests)
23 #:use-module (gnu system)
24 #:use-module (gnu system vm)
25 #:use-module (gnu services)
26 #:use-module (gnu services mail)
27 #:use-module (gnu services networking)
28 #:use-module (guix gexp)
29 #:use-module (guix store)
30 #:use-module (ice-9 ftw)
31 #:export (%test-opensmtpd
35 (simple-operating-system
37 (service opensmtpd-service-type
38 (opensmtpd-configuration
40 (plain-file "smtpd.conf" "
42 accept from any for local deliver to mbox
45 (define (run-opensmtpd-test)
46 "Return a test of an OS running OpenSMTPD service."
49 (operating-system (marionette-operating-system
51 #:imported-modules '((gnu services herd))))
52 (port-forwardings '((1025 . 25)))))
55 (with-imported-modules '((gnu build marionette))
57 (use-modules (rnrs base)
61 (gnu build marionette))
64 (make-marionette '(#$vm)))
66 (define (read-reply-code port)
67 "Read a SMTP reply from PORT and return its reply code."
68 (let* ((line (read-line port))
69 (mo (string-match "([0-9]+)([ -]).*" line))
70 (code (string->number (match:substring mo 1)))
71 (finished? (string= " " (match:substring mo 2))))
74 (read-reply-code port))))
79 (test-begin "opensmptd")
81 (test-assert "service is running"
84 (use-modules (gnu services herd))
85 (start-service 'smtpd)
89 (test-assert "mbox is empty"
91 '(and (file-exists? "/var/mail")
92 (not (file-exists? "/var/mail/root")))
95 (test-eq "accept an email"
97 (let* ((smtp (socket AF_INET SOCK_STREAM 0))
98 (addr (make-socket-address AF_INET INADDR_LOOPBACK 1025)))
101 (read-reply-code smtp) ;220
103 (write-line "EHLO somehost" smtp)
104 (read-reply-code smtp) ;250
106 (write-line "MAIL FROM: <someone>" smtp)
107 (read-reply-code smtp) ;250
108 ;; Set recipient email.
109 (write-line "RCPT TO: <root>" smtp)
110 (read-reply-code smtp) ;250
112 (write-line "DATA" smtp)
113 (read-reply-code smtp) ;354
114 (write-line "Subject: Hello" smtp)
116 (write-line "Nice to meet you!" smtp)
117 (write-line "." smtp)
118 (read-reply-code smtp) ;250
120 (write-line "QUIT" smtp)
121 (read-reply-code smtp) ;221
125 (test-assert "mail arrived"
128 (use-modules (ice-9 popen)
131 (define (queue-empty?)
134 (open-input-pipe "smtpctl show queue"))))
138 (file-exists? "/var/mail/root")
139 (begin (sleep 1) (wait)))))
143 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
145 (gexp->derivation "opensmtpd-test" test))
147 (define %test-opensmtpd
150 (description "Send an email to a running OpenSMTPD server.")
151 (value (run-opensmtpd-test))))
155 (simple-operating-system
156 (dhcp-client-service)
157 (service mail-aliases-service-type '())
158 (service exim-service-type
161 (plain-file "exim.conf" "
162 primary_hostname = komputilo
163 domainlist local_domains = @
164 domainlist relay_to_domains =
165 hostlist relay_from_hosts = localhost
169 acl_smtp_rcpt = acl_check_rcpt
170 acl_smtp_data = acl_check_data
180 (define (run-exim-test)
181 "Return a test of an OS running an Exim service."
184 (operating-system (marionette-operating-system
186 #:imported-modules '((gnu services herd))))
187 (port-forwardings '((1025 . 25)))))
190 (with-imported-modules '((gnu build marionette)
193 (use-modules (rnrs base)
198 (gnu build marionette))
201 (make-marionette '(#$vm)))
203 (define (read-reply-code port)
204 "Read a SMTP reply from PORT and return its reply code."
205 (let* ((line (read-line port))
206 (mo (string-match "([0-9]+)([ -]).*" line))
207 (code (string->number (match:substring mo 1)))
208 (finished? (string= " " (match:substring mo 2))))
211 (read-reply-code port))))
213 (define smtp (socket AF_INET SOCK_STREAM 0))
214 (define addr (make-socket-address AF_INET INADDR_LOOPBACK 1025))
221 (test-assert "service is running"
224 (use-modules (gnu services herd))
225 (start-service 'exim)
229 (sleep 1) ;; give the service time to start talking
233 (test-eq "greeting received"
234 220 (read-reply-code smtp))
236 (write-line "EHLO somehost" smtp)
237 (test-eq "greeting successful"
238 250 (read-reply-code smtp))
240 (write-line "MAIL FROM: test@example.com" smtp)
241 (test-eq "sender set"
242 250 (read-reply-code smtp)) ;250
243 ;; Set recipient email.
244 (write-line "RCPT TO: root@komputilo" smtp)
245 (test-eq "recipient set"
246 250 (read-reply-code smtp)) ;250
248 (write-line "DATA" smtp)
249 (test-eq "data begun"
250 354 (read-reply-code smtp)) ;354
251 (write-line "Subject: Hello" smtp)
253 (write-line "Nice to meet you!" smtp)
254 (write-line "." smtp)
255 (test-eq "message sent"
256 250 (read-reply-code smtp)) ;250
258 (write-line "QUIT" smtp)
259 (test-eq "quit successful"
260 221 (read-reply-code smtp)) ;221
263 (test-eq "the email is received"
267 (use-modules (ice-9 ftw))
268 (length (scandir "/var/spool/exim/msglog"
269 (lambda (x) (not (string-prefix? "." x))))))
273 (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
275 (gexp->derivation "exim-test" test))
280 (description "Send an email to a running an Exim server.")
281 (value (run-exim-test))))