Comments only, no behaviour changed. Each main.cf/master.cf parameter the
build sets, the wrapper's and the reload hook's reliance on Postfix 3.7.11
(postfix-script, master.5, postconf.5, cleanup_init.c, smtpd_peer.c,
README_FILES), supervisor 4.2.5 (process.py, options.py, events.rst),
logrotate 3.21.0, OpenDKIM's config, Cyrus SASL's sasldb, rspamd 3.11.1
(milter_headers.lua, multimap, the map watcher), Docker Compose, CoreDNS
and certbot now say where that is written. Measurements already there stay
measurements ("date not recorded" where none was); hand-composed fixtures
say so.
Contradictions left for their own commits: C-P31 cleanup's size limit,
C-P42 master outside supervisor's signal, C-V5/V6 startsecs, C-V10,
C-S3/Q3 sasldb written in place, C-Q4/A1 certbot's symlinks, C-R7 rspamd
skips local clients but the signature routine does not, C-P8, C-R4, C-R12,
C-M7, C-E2, C-K8/K9, C-D1.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
81 lines
2.9 KiB
Go
81 lines
2.9 KiB
Go
package e2e
|
|
|
|
import (
|
|
"fmt"
|
|
"html"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
var sendLogDetailsRe = regexp.MustCompile(`href="(/outbound/log/\d+[^"]*)"`)
|
|
|
|
// firstDeliveryPage returns the address of the page of the newest row in the
|
|
// sender domain's send log.
|
|
func firstDeliveryPage(sc *scenario) (string, error) {
|
|
rows, err := sc.panel.sendLogRows(senderDomain, "")
|
|
if err != nil {
|
|
return "", fmt.Errorf("read the send log: %w", err)
|
|
}
|
|
m := sendLogDetailsRe.FindStringSubmatch(rows)
|
|
if m == nil {
|
|
return "", fmt.Errorf("no Details link in the send log:\n%s", rows)
|
|
}
|
|
return html.UnescapeString(m[1]), nil
|
|
}
|
|
|
|
// testDeliveryLogSurvivesRotation checks that a message's page still lists
|
|
// what Postfix wrote about it after mail.log has been rotated: the lines are
|
|
// kept in the database by the log tailer, not searched for in the current
|
|
// file (architecture.md § Log tailer, Stored lines). The message is the first
|
|
// one delivered, whose page send_verify_dkim_and_status noted.
|
|
func testDeliveryLogSurvivesRotation(t *testing.T, sc *scenario) {
|
|
page := sc.deliveryPage
|
|
|
|
// What the page has to show: the line that opened the queue id and the
|
|
// delivery line. The tailer has read both - the row is "sent" - but it
|
|
// writes them one at a time, so the page is polled rather than read once.
|
|
wanted := []string{"client=", "status=sent"}
|
|
shows := func() (bool, error) {
|
|
_, body, err := sc.panel.get(page)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
for _, w := range wanted {
|
|
if !strings.Contains(body, w) {
|
|
return false, fmt.Errorf("%s does not show a %q line", page, w)
|
|
}
|
|
}
|
|
return true, nil
|
|
}
|
|
if err := waitFor("the message's page to list its log lines", 15*time.Second, 500*time.Millisecond, shows); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// The rotation ends with `postfix reload`, which fails while Postfix is
|
|
// still starting - and this step follows one that restarts the container.
|
|
// (Postfix 3.7.11, conf/postfix-script: "reload" and "status" both test
|
|
// "master -t" and exit 1 while master does not hold its pid lock.)
|
|
if err := waitFor("Postfix to be running", 30*time.Second, 500*time.Millisecond, func() (bool, error) {
|
|
if _, err := h.execIn("selfpost", "postfix", "status"); err != nil {
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := h.execIn("selfpost", "logrotate", "-f", "/etc/logrotate.d/mail"); err != nil {
|
|
t.Fatalf("logrotate -f: %v", err)
|
|
}
|
|
// The current file must no longer hold the delivery line, or the page
|
|
// finding it there would prove nothing. grep exits 1 on no match.
|
|
if out, err := h.execIn("selfpost", "sh", "-c", "grep -c 'status=sent' /data/log/mail.log || true"); err != nil || strings.TrimSpace(out) != "0" {
|
|
t.Fatalf("mail.log still holds delivery lines after the rotation (count=%q err=%v)", strings.TrimSpace(out), err)
|
|
}
|
|
|
|
if ok, err := shows(); !ok {
|
|
t.Fatalf("after mail.log was rotated: %v", err)
|
|
}
|
|
}
|