audit 4: a deleted domain says so, the Outbound log filters by status and day
test / test (push) Canceled after 0s

L17: past DeleteDomain both rebuilds run, their errors joined under
domain.ErrDeletedIncomplete; the key is removed only when OpenDKIM's tables
were rebuilt (they may still name it otherwise); the domain list says the
domain is deleted and that Reload configuration finishes it, not "internal
error". Tests in domain (the tables failing, the sender map failing) and
handlers.

The Outbound log's status and day filters (owner, 2026-10-13; the mockup
first, 80e3979): view.OutLogFilter carried by the poll, the pages, the rows'
links and the message's way back; SendLogFilter.Status, Since, Until (whole
UTC days, as the Inbound log's); rejected is the three refusals together; a
status not in the list is no narrowing. Tests: the filters through the
handler, the poll and the way back; the day boundaries in store.

The plan's milter-socket step is ticked: done in 2.5.2 (98e09fe).

Tested on the test server: go vet + go test of 25 packages, make e2e (all
pass, 642 s) on this tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-15 11:34:24 +03:00
co-authored by Claude Opus 5.5
parent 80e3979748
commit 2b8e0c086d
15 changed files with 378 additions and 52 deletions
+45
View File
@@ -3,6 +3,7 @@ package store
import (
"strings"
"testing"
"time"
)
// explain returns SQLite's plan for query, one step a line.
@@ -111,3 +112,47 @@ func TestSendLogQueriesUseTheirIndexes(t *testing.T) {
}
}
}
// The Outbound log's days are whole UTC days: from the first's midnight up
// to, not including, midnight after the last; the status is a row's.
func TestSendLogFilterDaysAndStatus(t *testing.T) {
s := openTestStore(t)
stamps := []string{"2026-09-13T23:59:59Z", "2026-09-14T00:00:00Z", "2026-09-21T23:59:59Z", "2026-09-22T00:00:00Z"}
for i, at := range stamps {
if err := s.InsertQueued(SendLogEntry{QueueID: "Q" + at[:2] + string(rune('A'+i)), Domain: "d.example", From: "a@d.example", To: "b@x.example"}); err != nil {
t.Fatal(err)
}
if _, err := s.db.Exec(`UPDATE send_log SET created_at = ? WHERE id = (SELECT MAX(id) FROM send_log)`, at); err != nil {
t.Fatal(err)
}
}
if _, err := s.db.Exec(`UPDATE send_log SET status = 'sent' WHERE created_at = '2026-09-14T00:00:00Z'`); err != nil {
t.Fatal(err)
}
day := func(d int) time.Time { return time.Date(2026, 9, d, 15, 0, 0, 0, time.FixedZone("x", 3*3600)) }
got := func(f SendLogFilter) []string {
f.AllDomains = true
rows, err := s.QuerySendLog(f, 10, 0)
if err != nil {
t.Fatal(err)
}
n, err := s.CountSendLog(f)
if err != nil || n != int64(len(rows)) {
t.Fatalf("count %d, %v; rows %d", n, err, len(rows))
}
var out []string
for _, r := range rows {
out = append(out, r.CreatedAt.UTC().Format(time.RFC3339))
}
return out
}
if g := got(SendLogFilter{Since: day(14), Until: day(21)}); strings.Join(g, " ") != "2026-09-21T23:59:59Z 2026-09-14T00:00:00Z" {
t.Errorf("14 to 21 = %v", g)
}
if g := got(SendLogFilter{Status: StatusSent}); strings.Join(g, " ") != "2026-09-14T00:00:00Z" {
t.Errorf("sent = %v", g)
}
if g := got(SendLogFilter{Status: StatusQueued, Until: day(13)}); strings.Join(g, " ") != "2026-09-13T23:59:59Z" {
t.Errorf("queued until 13 = %v", g)
}
}