99 lines
3.0 KiB
Go
99 lines
3.0 KiB
Go
package relay
|
|
|
|
import (
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"mailgoserver/internal/db"
|
|
"mailgoserver/internal/mailstore"
|
|
)
|
|
|
|
func TestBuildBounceMessageContainsFailureDetails(t *testing.T) {
|
|
content, messageID := buildBounceMessage("mail.example.com", "sender@example.com", "Hello", "orig-id@example.com", []Result{
|
|
{Recipient: "nobody@remote.example", ErrorMessage: "MX lookup failed", ErrorCode: "MX"},
|
|
})
|
|
if messageID == "" {
|
|
t.Fatal("expected a non-empty bounce Message-ID")
|
|
}
|
|
for _, want := range []string{
|
|
"To: sender@example.com",
|
|
"Subject: Undelivered Mail Returned to Sender",
|
|
"From: Mail Delivery System <mailer-daemon@mail.example.com>",
|
|
"Auto-Submitted: auto-replied",
|
|
"nobody@remote.example",
|
|
"MX lookup failed",
|
|
"Subject: Hello",
|
|
"Message-ID: <orig-id@example.com>",
|
|
} {
|
|
if !strings.Contains(content, want) {
|
|
t.Errorf("expected bounce content to contain %q, got:\n%s", want, content)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSendBounceNoOpWithoutSenderOrFailures(t *testing.T) {
|
|
r := &Relay{Hostname: "mail.example.com"}
|
|
if err := r.SendBounce("", "subj", "id", []Result{{Recipient: "x@example.com", ErrorMessage: "boom"}}); err != nil {
|
|
t.Fatalf("expected nil error for empty sender, got %v", err)
|
|
}
|
|
if err := r.SendBounce("sender@example.com", "subj", "id", nil); err != nil {
|
|
t.Fatalf("expected nil error for no failures, got %v", err)
|
|
}
|
|
}
|
|
|
|
// newTestMailbox mirrors mailstore's own test helper of the same name — kept local
|
|
// since it's unexported there and this package needs its own small Store+mailbox
|
|
// fixture to test SendBounce's local-delivery shortcut.
|
|
func newTestMailbox(t *testing.T, email string) (*mailstore.Store, int64) {
|
|
t.Helper()
|
|
database, err := db.Open(filepath.Join(t.TempDir(), "test.db"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { database.Close() })
|
|
|
|
domainID, err := database.CreateDomain("example.com")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s := mailstore.New(database, mailstore.GenerateDEK(), t.TempDir())
|
|
dek := mailstore.GenerateDEK()
|
|
wrapped, nonce, err := s.WrapDEK(dek)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
hash, err := db.HashPassword("irrelevant-portal-password")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
mailboxID, err := database.CreateMailbox(email, hash, domainID, 1<<30, wrapped, nonce)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return s, mailboxID
|
|
}
|
|
|
|
func TestSendBounceDeliversLocallyWhenRecipientIsLocalMailbox(t *testing.T) {
|
|
store, mailboxID := newTestMailbox(t, "sender@example.com")
|
|
r := &Relay{Hostname: "mail.example.com", Mailstore: store, Logger: nil}
|
|
|
|
err := r.SendBounce("sender@example.com", "Hello", "orig-id@example.com", []Result{
|
|
{Recipient: "nobody@remote.example", ErrorMessage: "MX lookup failed", ErrorCode: "MX"},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("SendBounce: %v", err)
|
|
}
|
|
|
|
inbox, err := store.DB.ListMessagesInFolder(mailboxID, "INBOX")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(inbox) != 1 {
|
|
t.Fatalf("expected 1 bounce message in INBOX, got %d", len(inbox))
|
|
}
|
|
if inbox[0].CachedSubject != "Undelivered Mail Returned to Sender" {
|
|
t.Errorf("bounce subject = %q", inbox[0].CachedSubject)
|
|
}
|
|
}
|