127 lines
4.0 KiB
Go
127 lines
4.0 KiB
Go
package smtp
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestSendReturnsConfigurationErrorWhenSMTPMissing(t *testing.T) {
|
|
mailer := NewSMTPMailer(SMTPConfig{Host: "", Port: 587, From: "noreply@example.com", Mode: SMTPModeTLS})
|
|
|
|
err := mailer.Send(context.Background(), "to@example.com", "subject", "<p>body</p>", "body")
|
|
if err == nil {
|
|
t.Fatal("expected configuration error")
|
|
}
|
|
if !strings.Contains(err.Error(), "smtp is not configured") {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSendReturnsDeadlineExceededForExpiredContext(t *testing.T) {
|
|
mailer := NewSMTPMailer(SMTPConfig{Host: "smtp.example.com", Port: 587, From: "noreply@example.com", Mode: SMTPModeTLS})
|
|
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(-time.Second))
|
|
defer cancel()
|
|
|
|
err := mailer.Send(ctx, "to@example.com", "subject", "<p>body</p>", "body")
|
|
if err == nil {
|
|
t.Fatal("expected context deadline exceeded")
|
|
}
|
|
if err != context.DeadlineExceeded {
|
|
t.Fatalf("expected context deadline exceeded, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLoginAuthNextHandlesChallenges(t *testing.T) {
|
|
auth := loginAuth{username: "alice", password: "s3cret"}
|
|
|
|
proto, initial, err := auth.Start(nil)
|
|
if err != nil {
|
|
t.Fatalf("unexpected start error: %v", err)
|
|
}
|
|
if proto != "LOGIN" {
|
|
t.Fatalf("expected LOGIN auth proto, got %q", proto)
|
|
}
|
|
if len(initial) != 0 {
|
|
t.Fatalf("expected empty initial response, got %q", string(initial))
|
|
}
|
|
|
|
value, err := auth.Next([]byte("Username:"), true)
|
|
if err != nil {
|
|
t.Fatalf("unexpected username challenge error: %v", err)
|
|
}
|
|
if string(value) != "alice" {
|
|
t.Fatalf("expected username response alice, got %q", string(value))
|
|
}
|
|
|
|
value, err = auth.Next([]byte("UGFzc3dvcmQ6"), true)
|
|
if err != nil {
|
|
t.Fatalf("unexpected password challenge error: %v", err)
|
|
}
|
|
if string(value) != "s3cret" {
|
|
t.Fatalf("expected password response s3cret, got %q", string(value))
|
|
}
|
|
}
|
|
|
|
func TestLoginAuthNextHandlesTerminalAndUnexpectedChallenge(t *testing.T) {
|
|
auth := loginAuth{username: "alice", password: "s3cret"}
|
|
|
|
value, err := auth.Next([]byte("ignored"), false)
|
|
if err != nil {
|
|
t.Fatalf("expected nil error when more=false, got %v", err)
|
|
}
|
|
if value != nil {
|
|
t.Fatalf("expected nil value when more=false, got %q", string(value))
|
|
}
|
|
|
|
if _, err := auth.Next([]byte("realm"), true); err == nil {
|
|
t.Fatal("expected error for unexpected login challenge")
|
|
}
|
|
}
|
|
|
|
func TestBuildMIMEMessageContainsMultipartSections(t *testing.T) {
|
|
msg := buildMIMEMessage("from@example.com", "to@example.com", "Subject", "plain body", "<p>html body</p>")
|
|
|
|
checks := []string{
|
|
"From: from@example.com",
|
|
"To: to@example.com",
|
|
"Subject: Subject",
|
|
"MIME-Version: 1.0",
|
|
"Content-Type: text/plain; charset=UTF-8",
|
|
"plain body",
|
|
"Content-Type: text/html; charset=UTF-8",
|
|
"<p>html body</p>",
|
|
}
|
|
for _, snippet := range checks {
|
|
if !strings.Contains(msg, snippet) {
|
|
t.Fatalf("expected MIME message to contain %q", snippet)
|
|
}
|
|
}
|
|
if !strings.Contains(msg, "\r\n") {
|
|
t.Fatal("expected CRLF separators in MIME message")
|
|
}
|
|
|
|
if !strings.Contains(msg, "Content-Type: multipart/alternative; boundary=mime-boundary-") {
|
|
t.Fatalf("expected random mime boundary header, got %q", msg)
|
|
}
|
|
if !strings.Contains(msg, "--mime-boundary-") {
|
|
t.Fatalf("expected mime boundary delimiters in message, got %q", msg)
|
|
}
|
|
}
|
|
|
|
func TestDialHelpersReturnDeadlineExceededWhenDeadlineHasPassed(t *testing.T) {
|
|
deadline := time.Now().Add(-time.Second)
|
|
ctx := context.Background()
|
|
|
|
if _, err := dialPlain(ctx, "smtp.example.com:25", "smtp.example.com", deadline); err != context.DeadlineExceeded {
|
|
t.Fatalf("dialPlain expected context deadline exceeded, got %v", err)
|
|
}
|
|
if _, err := dialSSL(ctx, "smtp.example.com:465", "smtp.example.com", deadline); err != context.DeadlineExceeded {
|
|
t.Fatalf("dialSSL expected context deadline exceeded, got %v", err)
|
|
}
|
|
if _, err := dialStartTLS(ctx, "smtp.example.com:587", "smtp.example.com", deadline); err != context.DeadlineExceeded {
|
|
t.Fatalf("dialStartTLS expected context deadline exceeded, got %v", err)
|
|
}
|
|
}
|