Subject: Re: Invalid 'location' field generated in dovecot configuration

From: Pierre Langlois <[email-masked]>
Date: Thu, 01 Dec 2022 21:55:27 +0000

Hi all!

As suggested by mirai off-list, it would be nice to have a test that
would have caught the issue. How do people feel about something along
the following patch? The idea is to use namespaces in the dovecot config
to declare the INBOX and another additional mailbox.

The bug is quite obscure and not really about dovecot itself, so I don't
think adding such a test is strictly necessary, maybe more tests for the
configuration macro would be good instead. But I figured expanding the
dovecot system test can't hurt. Let me know if you agree and I'll format
it properly.

diff --git a/gnu/tests/mail.scm b/gnu/tests/mail.scm
index f13751b72f..8a2dbd798f 100644
--- a/gnu/tests/mail.scm
+++ b/gnu/tests/mail.scm
@@ -301,8 +301,19 @@ (define %dovecot-os
                      (auth-anonymous-username "alice")
                      (mail-location
                       (string-append "maildir:~/Maildir"
-                                     ":INBOX=~/Maildir/INBOX"
-                                     ":LAYOUT=fs"))))))
+                                     ":LAYOUT=fs"))
+                     (namespaces
+                      (list
+                       (namespace-configuration
+                        (name "INBOX")
+                        (inbox? #t)
+                        (separator "/")
+                        (location "maildir:~/Maildir/INBOX"))
+                       (namespace-configuration
+                        (name "guix-devel")
+                        (separator "/")
+                        (prefix "guix-devel/")
+                        (location "maildir:~/Maildir/guix-devel"))))))))
 
 (define (run-dovecot-test)
   "Return a test of an OS running Dovecot service."
@@ -351,9 +362,10 @@ (define message "From: [email-masked]\n\
               (marionette-eval `(file-exists? (string-append "/proc/" ,pid))
                                marionette)))
 
-          (test-assert "accept an email"
+          (define-syntax-rule (with-imap-connection imap exp ...)
             (let ((imap (socket AF_INET SOCK_STREAM 0))
-                  (addr (make-socket-address AF_INET INADDR_LOOPBACK 8143)))
+                  (addr (make-socket-address AF_INET INADDR_LOOPBACK 8143))
+                  (body (lambda (imap) exp ...)))
               (connect imap addr)
               ;; Be greeted.
               (read-line imap) ;OK
@@ -362,6 +374,43 @@ (define message "From: [email-masked]\n\
               (read-line imap) ;+
               (write-line "c2lyaGM=" imap)
               (read-line imap) ;OK
+
+              (let ((ok (body imap)))
+                ;; Logout
+                (write-line "a LOGOUT" imap)
+                (close imap)
+                ok)))
+
+          (define (marionette-read-new-mail mailbox marionette)
+            (marionette-eval
+             `(begin
+                (use-modules (ice-9 ftw)
+                             (ice-9 match))
+                (match (scandir ,mailbox)
+                  (("." ".." message-file)
+                   (call-with-input-file
+                       (string-append ,mailbox message-file)
+                     get-string-all))))
+             marionette))
+
+          (test-assert "accept an email"
+            (with-imap-connection imap
+              ;; Append a message to the INBOX mailbox
+              (write-line (format #f "a APPEND INBOX {~a}"
+                                  (number->string (message-length message)))
+                          imap)
+              (read-line imap) ;+
+              (write-line message imap)
+              (read-line imap) ;OK
+              #t))
+
+          (test-equal "mail arrived"
+            message
+            (marionette-read-new-mail "/home/alice/Maildir/INBOX/new/"
+                                      marionette))
+
+          (test-assert "accept an email in fresh mailbox"
+            (with-imap-connection imap
               ;; Create a TESTBOX mailbox
               (write-line "a CREATE TESTBOX" imap)
               (read-line imap) ;OK
@@ -372,24 +421,16 @@ (define message "From: [email-masked]\n\
               (read-line imap) ;+
               (write-line message imap)
               (read-line imap) ;OK
-              ;; Logout
-              (write-line "a LOGOUT" imap)
-              (close imap)
               #t))
 
-          (test-equal "mail arrived"
+          (test-equal "mail arrived in fresh mailbox"
             message
-            (marionette-eval
-             '(begin
-                (use-modules (ice-9 ftw)
-                             (ice-9 match))
-                (let ((TESTBOX/new "/home/alice/Maildir/TESTBOX/new/"))
-                  (match (scandir TESTBOX/new)
-                    (("." ".." message-file)
-                     (call-with-input-file
-                         (string-append TESTBOX/new message-file)
-                       get-string-all)))))
-             marionette))
+            (marionette-read-new-mail "/home/alice/Maildir/TESTBOX/new/"
+                                      marionette))
+
+          (test-assert "mailbox exists"
+            (marionette-eval `(file-exists? "/home/alice/Maildir/guix-devel")
+                             marionette))
 
           (test-end))))

Thanks,
Pierre