Files
verdande/internal/mail/mail_test.go
T

77 lines
3.1 KiB
Go
Raw Normal View History

package mail
import (
"bytes"
"context"
"log/slog"
"strings"
"testing"
"time"
"github.com/kristianwind/verdande/internal/config"
)
// TestEveryMessageCarriesTheEditionsOwnName.
//
// These three letters are the only thing this program sends to an address its
// operator does not control, and an invitation from an urd instance that says
// "verdande" is a letter to a stranger about a program they are not being invited
// to. The name was a field with a value and no reader until 2026-10-07 — the three
// places that needed it had the word written out instead — so the assertion that
// matters is not "it says urd" but "it does not say the other one".
//
// Measured through the unconfigured path on purpose: with no SMTP host, send()
// logs the whole message at warn level and returns, so the subject and the body
// can be read as the recipient would get them without a mail server in the test.
func TestEveryMessageCarriesTheEditionsOwnName(t *testing.T) {
for _, tc := range []struct{ name, other string }{
{"verdande", "urd"},
{"urd", "verdande"},
} {
t.Run(tc.name, func(t *testing.T) {
var buf bytes.Buffer
s := New(config.SMTP{}, "https://example.dk", tc.name,
slog.New(slog.NewTextHandler(&buf, &slog.HandlerOptions{Level: slog.LevelWarn})))
ctx := context.Background()
if err := s.SendInvite(ctx, "ny@example.dk", "Kristian", "", "https://example.dk/i/abc", time.Hour); err != nil {
t.Fatalf("SendInvite: %v", err)
}
if err := s.SendPasswordReset(ctx, "ny@example.dk", "Kristian", "https://example.dk/r/abc", time.Hour); err != nil {
t.Fatalf("SendPasswordReset: %v", err)
}
if err := s.SendReminder(ctx, "ny@example.dk", "Kristian", "Ring til tandlægen", "https://example.dk/opgave/1"); err != nil {
t.Fatalf("SendReminder: %v", err)
}
got := buf.String()
if n := strings.Count(got, `msg="no SMTP host configured`); n != 3 {
t.Fatalf("expected three logged messages, got %d — the test is reading the wrong thing", n)
}
if !strings.Contains(got, tc.name) {
t.Errorf("no message mentions %q", tc.name)
}
if strings.Contains(got, tc.other) {
t.Errorf("a message mentions %q on a %s instance; the name is hard-coded somewhere", tc.other, tc.name)
}
t.Logf("%s: %d bytes of mail across three messages", tc.name, len(got))
})
}
}
// TestAnInviteWithoutAProjectNamesTheProgram pins the one place the name is the
// *subject* of the sentence rather than a signature: an invitation to the instance
// itself, with no project, reads "has invited you to <program>".
func TestAnInviteWithoutAProjectNamesTheProgram(t *testing.T) {
var buf bytes.Buffer
s := New(config.SMTP{}, "https://example.dk", "urd",
slog.New(slog.NewTextHandler(&buf, &slog.HandlerOptions{Level: slog.LevelWarn})))
if err := s.SendInvite(context.Background(), "ny@example.dk", "Kristian", "", "https://example.dk/i/abc", time.Hour); err != nil {
t.Fatalf("SendInvite: %v", err)
}
if !strings.Contains(buf.String(), "inviteret dig til urd") {
t.Errorf("the invite does not read \"inviteret dig til urd\":\n%s", buf.String())
}
}