test: tests Go para funciones email SMTP
Tests para builders puros (build_html, build_text, with_attachment), template_render, smtp_connect y smtp_send con mock TCP server. Todos los tests pasan: 18 casos cubriendo pureza, inmutabilidad y envio SMTP. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
package infra
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// startMockSMTPForSend starts a mock SMTP server and returns host/port separately.
|
||||
func startMockSMTPForSend(t *testing.T) (host string, port int, stop func()) {
|
||||
t.Helper()
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("mock smtp listen: %v", err)
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go handleMockSMTP(conn)
|
||||
}
|
||||
}()
|
||||
h, ps, _ := net.SplitHostPort(ln.Addr().String())
|
||||
p := 0
|
||||
fmt.Sscanf(ps, "%d", &p)
|
||||
return h, p, func() { ln.Close() }
|
||||
}
|
||||
|
||||
|
||||
func TestSMTPSend(t *testing.T) {
|
||||
t.Run("envia mensaje texto plano via mock smtp", func(t *testing.T) {
|
||||
host, port, stop := startMockSMTPForSend(t)
|
||||
defer stop()
|
||||
|
||||
cfg := SMTPConfig{Host: host, Port: port, TLSMode: ""}
|
||||
client, err := SMTPConnect(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("SMTPConnect: %v", err)
|
||||
}
|
||||
defer client.Quit()
|
||||
|
||||
msg := EmailBuildText("alice@example.com", []string{"bob@example.com"}, "Test", "Hello Bob")
|
||||
if err := SMTPSend(client, msg); err != nil {
|
||||
t.Fatalf("SMTPSend: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("envia mensaje html via mock smtp", func(t *testing.T) {
|
||||
host, port, stop := startMockSMTPForSend(t)
|
||||
defer stop()
|
||||
|
||||
cfg := SMTPConfig{Host: host, Port: port, TLSMode: ""}
|
||||
client, err := SMTPConnect(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("SMTPConnect: %v", err)
|
||||
}
|
||||
defer client.Quit()
|
||||
|
||||
msg := EmailBuildHTML("alice@example.com", []string{"bob@example.com"}, "HTML Test", "<b>Hello</b>")
|
||||
if err := SMTPSend(client, msg); err != nil {
|
||||
t.Fatalf("SMTPSend: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("envia con adjunto via mock smtp", func(t *testing.T) {
|
||||
host, port, stop := startMockSMTPForSend(t)
|
||||
defer stop()
|
||||
|
||||
cfg := SMTPConfig{Host: host, Port: port, TLSMode: ""}
|
||||
client, err := SMTPConnect(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("SMTPConnect: %v", err)
|
||||
}
|
||||
defer client.Quit()
|
||||
|
||||
msg := EmailBuildText("alice@example.com", []string{"bob@example.com"}, "Att Test", "See attachment")
|
||||
att := EmailAttachment{Filename: "data.txt", ContentType: "text/plain", Data: []byte("file content")}
|
||||
msg = EmailWithAttachment(msg, att)
|
||||
|
||||
if err := SMTPSend(client, msg); err != nil {
|
||||
t.Fatalf("SMTPSend with attachment: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestExtractAddr tests the internal extractAddr helper.
|
||||
func TestExtractAddr(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
want string
|
||||
}{
|
||||
{"Alice <alice@example.com>", "alice@example.com"},
|
||||
{"bob@example.com", "bob@example.com"},
|
||||
{" carol@example.com ", "carol@example.com"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got := extractAddr(c.input)
|
||||
if got != c.want {
|
||||
t.Errorf("extractAddr(%q) = %q, want %q", c.input, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestBuildMIME tests the MIME builder with different body combinations.
|
||||
func TestBuildMIME(t *testing.T) {
|
||||
t.Run("solo texto plano", func(t *testing.T) {
|
||||
msg := EmailBuildText("a@a.com", []string{"b@b.com"}, "Subj", "Hello plain")
|
||||
body, err := buildMIME(msg)
|
||||
if err != nil {
|
||||
t.Fatalf("buildMIME: %v", err)
|
||||
}
|
||||
s := string(body)
|
||||
if !strings.Contains(s, "text/plain") {
|
||||
t.Errorf("expected text/plain in MIME, got:\n%s", s)
|
||||
}
|
||||
if !strings.Contains(s, "Hello plain") {
|
||||
t.Errorf("expected body text in MIME, got:\n%s", s)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("solo html", func(t *testing.T) {
|
||||
msg := EmailBuildHTML("a@a.com", []string{"b@b.com"}, "Subj", "<b>Bold</b>")
|
||||
body, err := buildMIME(msg)
|
||||
if err != nil {
|
||||
t.Fatalf("buildMIME: %v", err)
|
||||
}
|
||||
s := string(body)
|
||||
if !strings.Contains(s, "text/html") {
|
||||
t.Errorf("expected text/html in MIME, got:\n%s", s)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("multipart con adjunto", func(t *testing.T) {
|
||||
msg := EmailBuildText("a@a.com", []string{"b@b.com"}, "Subj", "body")
|
||||
att := EmailAttachment{Filename: "f.pdf", ContentType: "application/pdf", Data: []byte("pdf")}
|
||||
msg = EmailWithAttachment(msg, att)
|
||||
body, err := buildMIME(msg)
|
||||
if err != nil {
|
||||
t.Fatalf("buildMIME: %v", err)
|
||||
}
|
||||
s := string(body)
|
||||
if !strings.Contains(s, "multipart/mixed") {
|
||||
t.Errorf("expected multipart/mixed in MIME, got:\n%s", s)
|
||||
}
|
||||
if !strings.Contains(s, "f.pdf") {
|
||||
t.Errorf("expected attachment filename in MIME, got:\n%s", s)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user