package view
import (
"fmt"
"strings"
"testing"
"time"
)
// ---- Outbound queue
// The page is the mockup's table, a row per recipient with its last reply and
// the link to the message, and it polls from its box; the retry policy sits
// under it, outside the poll.
func TestOutQueueShowsTheTableAndPollsItsBox(t *testing.T) {
out := renderSignedIn(t, "out-queue", outQueueFixture())
pageHas(t, "Outbound queue", out,
`
`) != 2 {
t.Error("the two recipients of a message without a send-log row should have an empty Details cell")
}
}
// A backlog is cut at maxQueueRows, oldest kept, and the foot says how many
// there are.
func TestOutQueueCutsALongBacklog(t *testing.T) {
t0 := time.Date(2026, 10, 18, 9, 0, 0, 0, time.Local)
var entries []QueueEntry
for i := 0; i < maxQueueRows+5; i++ {
entries = append(entries, QueueEntry{ID: fmt.Sprintf("Q%04d", i), Queue: "deferred", Arrival: t0.Add(time.Duration(i) * time.Minute), Recipient: "r@example.net"})
}
out := renderSignedIn(t, "out-queue", NewOutQueue(admin(), entries, ""))
pageHas(t, "long queue", out, "Q0000", fmt.Sprintf("Q%04d", maxQueueRows-1),
fmt.Sprintf("The oldest %d of %d recipients waiting.", maxQueueRows, maxQueueRows+5), `class="sp-box-foot"`)
pageLacks(t, "long queue", out, fmt.Sprintf("Q%04d", maxQueueRows))
}
// The policy is the page's, wherever it was read from: its facts, and a head
// that says so when they are the compiled-in defaults.
func TestOutQueueStatesTheRetryPolicy(t *testing.T) {
out := renderSignedIn(t, "out-queue", NewOutQueue(admin(), nil, "").WithRetryPolicy("10 minutes", "about 1 hour 7 minutes", "2 days", false))
pageHas(t, "Outbound queue", out,
`
How retries work
`, `This Postfix's policy, read at panel start`,
`
10 minutes`, `
doubling`, `capped at about 1 hour 7 minutes`,
`
2 days`, `
bounced`, `no attempt counter, only time`,
)
pageLacks(t, "Outbound queue", out, "Compiled-in defaults")
out = renderSignedIn(t, "out-queue", NewOutQueue(admin(), nil, "").WithRetryPolicy("5 minutes", "about 1 hour 7 minutes", "5 days", true))
pageHas(t, "Outbound queue", out, "Compiled-in defaults: the Postfix configuration could not be read")
pageLacks(t, "Outbound queue", out, "read at panel start")
}
// With nothing to list the box says why instead: the queue holds nothing, or
// it could not be read — and never both.
func TestOutQueueSaysWhyItHasNoRows(t *testing.T) {
out := renderSignedIn(t, "out-queue", NewOutQueue(admin(), nil, ""))
pageHas(t, "empty queue", out, `class="sp-empty"`, "Nothing is waiting. Every message has reached its receiving server.", "Refreshes on its own")
pageLacks(t, "empty queue", out, "
Inbound queue`,
`The same Postfix queue as outbound, filtered by recipient domain.`,
`id="in-queue" data-poll aria-live="polite" hx-get="/inbound/queue/fragment" hx-trigger="load" hx-swap="outerHTML"`,
`Nothing is waiting. Every accepted message has reached its upstream.`, `href="/help#inbound-queue"`,
`back to the original sender`,
)
rows := []QueueEntry{{ID: "IN0001", Queue: "deferred", Arrival: time.Date(2026, 10, 18, 9, 0, 0, 0, time.Local), Size: 5000,
Sender: "someone@example.net", Recipient: "staff@lists.example.com", Reason: "451 4.7.1 Greylisted"}}
out = renderSignedIn(t, "in-queue", NewInQueue(admin(), rows, ""))
pageHas(t, "Inbound queue", out, `1 message · 4.9 kB`, `| IN0001 | `, `staff@lists.example.com`, `451 4.7.1 Greylisted`,
`Last reply | `)
pageLacks(t, "Inbound queue", out, "Details", `sp-actions`)
}