mail.scm 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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>
  5. ;;;
  6. ;;; This file is part of GNU Guix.
  7. ;;;
  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.
  12. ;;;
  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.
  17. ;;;
  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/>.
  20. (define-module (gnu tests mail)
  21. #:use-module (gnu tests)
  22. #:use-module (gnu system)
  23. #:use-module (gnu system vm)
  24. #:use-module (gnu services)
  25. #:use-module (gnu services mail)
  26. #:use-module (gnu services networking)
  27. #:use-module (guix gexp)
  28. #:use-module (guix store)
  29. #:use-module (ice-9 ftw)
  30. #:export (%test-opensmtpd
  31. %test-exim))
  32. (define %opensmtpd-os
  33. (simple-operating-system
  34. (dhcp-client-service)
  35. (service opensmtpd-service-type
  36. (opensmtpd-configuration
  37. (config-file
  38. (plain-file "smtpd.conf" "
  39. listen on 0.0.0.0
  40. accept from any for local deliver to mbox
  41. "))))))
  42. (define (run-opensmtpd-test)
  43. "Return a test of an OS running OpenSMTPD service."
  44. (define vm
  45. (virtual-machine
  46. (operating-system (marionette-operating-system
  47. %opensmtpd-os
  48. #:imported-modules '((gnu services herd))))
  49. (port-forwardings '((1025 . 25)))))
  50. (define test
  51. (with-imported-modules '((gnu build marionette))
  52. #~(begin
  53. (use-modules (rnrs base)
  54. (srfi srfi-64)
  55. (ice-9 rdelim)
  56. (ice-9 regex)
  57. (gnu build marionette))
  58. (define marionette
  59. (make-marionette '(#$vm)))
  60. (define (read-reply-code port)
  61. "Read a SMTP reply from PORT and return its reply code."
  62. (let* ((line (read-line port))
  63. (mo (string-match "([0-9]+)([ -]).*" line))
  64. (code (string->number (match:substring mo 1)))
  65. (finished? (string= " " (match:substring mo 2))))
  66. (if finished?
  67. code
  68. (read-reply-code port))))
  69. (mkdir #$output)
  70. (chdir #$output)
  71. (test-begin "opensmptd")
  72. (test-assert "service is running"
  73. (marionette-eval
  74. '(begin
  75. (use-modules (gnu services herd))
  76. (start-service 'smtpd)
  77. #t)
  78. marionette))
  79. (test-assert "mbox is empty"
  80. (marionette-eval
  81. '(and (file-exists? "/var/mail")
  82. (not (file-exists? "/var/mail/root")))
  83. marionette))
  84. (test-eq "accept an email"
  85. #t
  86. (let* ((smtp (socket AF_INET SOCK_STREAM 0))
  87. (addr (make-socket-address AF_INET INADDR_LOOPBACK 1025)))
  88. (connect smtp addr)
  89. ;; Be greeted.
  90. (read-reply-code smtp) ;220
  91. ;; Greet the server.
  92. (write-line "EHLO somehost" smtp)
  93. (read-reply-code smtp) ;250
  94. ;; Set sender email.
  95. (write-line "MAIL FROM: <someone>" smtp)
  96. (read-reply-code smtp) ;250
  97. ;; Set recipient email.
  98. (write-line "RCPT TO: <root>" smtp)
  99. (read-reply-code smtp) ;250
  100. ;; Send message.
  101. (write-line "DATA" smtp)
  102. (read-reply-code smtp) ;354
  103. (write-line "Subject: Hello" smtp)
  104. (newline smtp)
  105. (write-line "Nice to meet you!" smtp)
  106. (write-line "." smtp)
  107. (read-reply-code smtp) ;250
  108. ;; Say goodbye.
  109. (write-line "QUIT" smtp)
  110. (read-reply-code smtp) ;221
  111. (close smtp)
  112. #t))
  113. (test-assert "mail arrived"
  114. (marionette-eval
  115. '(begin
  116. (use-modules (ice-9 popen)
  117. (ice-9 rdelim))
  118. (define (queue-empty?)
  119. (eof-object?
  120. (read-line
  121. (open-input-pipe "smtpctl show queue"))))
  122. (let wait ()
  123. (if (queue-empty?)
  124. (file-exists? "/var/mail/root")
  125. (begin (sleep 1) (wait)))))
  126. marionette))
  127. (test-end)
  128. (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
  129. (gexp->derivation "opensmtpd-test" test))
  130. (define %test-opensmtpd
  131. (system-test
  132. (name "opensmtpd")
  133. (description "Send an email to a running OpenSMTPD server.")
  134. (value (run-opensmtpd-test))))
  135. (define %exim-os
  136. (simple-operating-system
  137. (dhcp-client-service)
  138. (service mail-aliases-service-type '())
  139. (service exim-service-type
  140. (exim-configuration
  141. (config-file
  142. (plain-file "exim.conf" "
  143. primary_hostname = komputilo
  144. domainlist local_domains = @
  145. domainlist relay_to_domains =
  146. hostlist relay_from_hosts = localhost
  147. never_users =
  148. acl_smtp_rcpt = acl_check_rcpt
  149. acl_smtp_data = acl_check_data
  150. begin acl
  151. acl_check_rcpt:
  152. accept
  153. acl_check_data:
  154. accept
  155. "))))))
  156. (define (run-exim-test)
  157. "Return a test of an OS running an Exim service."
  158. (define vm
  159. (virtual-machine
  160. (operating-system (marionette-operating-system
  161. %exim-os
  162. #:imported-modules '((gnu services herd))))
  163. (port-forwardings '((1025 . 25)))))
  164. (define test
  165. (with-imported-modules '((gnu build marionette)
  166. (ice-9 ftw))
  167. #~(begin
  168. (use-modules (rnrs base)
  169. (srfi srfi-64)
  170. (ice-9 ftw)
  171. (ice-9 rdelim)
  172. (ice-9 regex)
  173. (gnu build marionette))
  174. (define marionette
  175. (make-marionette '(#$vm)))
  176. (define (read-reply-code port)
  177. "Read a SMTP reply from PORT and return its reply code."
  178. (let* ((line (read-line port))
  179. (mo (string-match "([0-9]+)([ -]).*" line))
  180. (code (string->number (match:substring mo 1)))
  181. (finished? (string= " " (match:substring mo 2))))
  182. (if finished?
  183. code
  184. (read-reply-code port))))
  185. (define smtp (socket AF_INET SOCK_STREAM 0))
  186. (define addr (make-socket-address AF_INET INADDR_LOOPBACK 1025))
  187. (mkdir #$output)
  188. (chdir #$output)
  189. (test-begin "exim")
  190. (test-assert "service is running"
  191. (marionette-eval
  192. '(begin
  193. (use-modules (gnu services herd))
  194. (start-service 'exim)
  195. #t)
  196. marionette))
  197. (sleep 1) ;; give the service time to start talking
  198. (connect smtp addr)
  199. ;; Be greeted.
  200. (test-eq "greeting received"
  201. 220 (read-reply-code smtp))
  202. ;; Greet the server.
  203. (write-line "EHLO somehost" smtp)
  204. (test-eq "greeting successful"
  205. 250 (read-reply-code smtp))
  206. ;; Set sender email.
  207. (write-line "MAIL FROM: test@example.com" smtp)
  208. (test-eq "sender set"
  209. 250 (read-reply-code smtp)) ;250
  210. ;; Set recipient email.
  211. (write-line "RCPT TO: root@komputilo" smtp)
  212. (test-eq "recipient set"
  213. 250 (read-reply-code smtp)) ;250
  214. ;; Send message.
  215. (write-line "DATA" smtp)
  216. (test-eq "data begun"
  217. 354 (read-reply-code smtp)) ;354
  218. (write-line "Subject: Hello" smtp)
  219. (newline smtp)
  220. (write-line "Nice to meet you!" smtp)
  221. (write-line "." smtp)
  222. (test-eq "message sent"
  223. 250 (read-reply-code smtp)) ;250
  224. ;; Say goodbye.
  225. (write-line "QUIT" smtp)
  226. (test-eq "quit successful"
  227. 221 (read-reply-code smtp)) ;221
  228. (close smtp)
  229. (test-eq "the email is received"
  230. 1
  231. (marionette-eval
  232. '(begin
  233. (use-modules (ice-9 ftw))
  234. (length (scandir "/var/spool/exim/msglog"
  235. (lambda (x) (not (string-prefix? "." x))))))
  236. marionette))
  237. (test-end)
  238. (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
  239. (gexp->derivation "exim-test" test))
  240. (define %test-exim
  241. (system-test
  242. (name "exim")
  243. (description "Send an email to a running an Exim server.")
  244. (value (run-exim-test))))