package handlers import ( "errors" "net/http" "strconv" "strings" "testing" "time" "github.com/mixeme/selfpost/internal/postfix" "github.com/mixeme/selfpost/internal/store" "github.com/mixeme/selfpost/internal/web/auth" ) // The two queues are one Postfix queue split by the recipient's domain. Their // markup is held to the mockups by the guards in internal/web/view; what is // checked here is the split, the link to the send-log row, and who may look. // stubQueue answers queueListing with msgs (or err) for the test. func stubQueue(t *testing.T, msgs []postfix.QueuedMessage, err error) { t.Helper() old := queueListing t.Cleanup(func() { queueListing = old }) queueListing = func() ([]postfix.QueuedMessage, error) { return msgs, err } } func TestQueuesSplitByRecipientDomain(t *testing.T) { s := newInboundLogStand(t) // inbound domains a.example.com, b.example.com if err := s.st.InsertQueued(store.SendLogEntry{QueueID: "OUT00001", Domain: "shop.example.org", AppLogin: "shop", From: "alerts@shop.example.org", To: "noc@example.net", Subject: "Hi"}); err != nil { t.Fatal(err) } rows, err := s.st.QuerySendLog(store.SendLogFilter{AllDomains: true}, 1, 0) if err != nil || len(rows) != 1 { t.Fatalf("query: %v (%d rows)", err, len(rows)) } at := time.Date(2026, 10, 18, 9, 0, 0, 0, time.UTC) stubQueue(t, []postfix.QueuedMessage{ {ID: "OUT00001", Queue: "deferred", Sender: "alerts@shop.example.org", Arrival: at, Size: 3174, Recipients: []postfix.QueuedRecipient{{Address: "NOC@example.net", DelayReason: "451 4.7.1 Greylisted"}}}, {ID: "IN000001", Queue: "deferred", Sender: "someone@example.net", Arrival: at, Size: 5000, Recipients: []postfix.QueuedRecipient{{Address: "alice@A.example.com", DelayReason: "connect to upstream.example.com[192.0.2.7]:25: Connection refused"}}}, {ID: "NOTE0001", Queue: "active", Sender: "postmaster@mail.example.org", Arrival: at, Size: 900, Recipients: []postfix.QueuedRecipient{{Address: "admin@example.net"}}}, }, nil) out := s.get(s.h.HandleMailQueue, "/outbound/queue", globalPrincipal).Body.String() has(t, "Outbound queue", out, "OUT00001", "451 4.7.1 Greylisted", `Details`, // matched without regard to case "NOTE0001", "Being delivered now", "2 messages") if strings.Contains(out, "IN000001") { t.Error("a recipient of an inbound domain is on the Outbound queue") } if strings.Count(out, ">Details") != 1 { t.Error("the panel's own message has no send-log row and should have no Details link") } in := s.get(s.h.HandleInboundQueue, "/inbound/queue", globalPrincipal).Body.String() has(t, "Inbound queue", in, "IN000001", "Connection refused", "1 message ยท 4.9 kB") for _, other := range []string{"OUT00001", "NOTE0001", ">Details"} { if strings.Contains(in, other) { t.Errorf("the Inbound queue shows %q", other) } } frag := s.get(s.h.HandleInboundQueueBody, "/inbound/queue/fragment", globalPrincipal).Body.String() if !strings.HasPrefix(frag, `