Files
imap-copier/internal/imapx/batch_test.go
T
vasyansk 2623bc8815 Reduce worker concurrency from 4 to 2
Reduce idle read timeout from 120s to 60s

Add batching for IMAP metadata fetches
2026-07-05 11:40:04 +07:00

55 lines
1.8 KiB
Go

package imapx
import (
"testing"
"github.com/emersion/go-imap/v2"
)
// metaBatches must tile the sequence 1..total into contiguous, non-overlapping
// windows of at most batchSize, covering every message exactly once. A single
// unbounded FETCH 1:* is what wedges large mailboxes; batching keeps each
// command short so the server stays responsive and ctx can be checked between
// windows.
func TestMetaBatches(t *testing.T) {
cases := []struct {
total, size uint32
want []imap.SeqRange
}{
{0, 1000, nil},
{1, 1000, []imap.SeqRange{{Start: 1, Stop: 1}}},
{1000, 1000, []imap.SeqRange{{Start: 1, Stop: 1000}}},
{1001, 1000, []imap.SeqRange{{Start: 1, Stop: 1000}, {Start: 1001, Stop: 1001}}},
{2500, 1000, []imap.SeqRange{{Start: 1, Stop: 1000}, {Start: 1001, Stop: 2000}, {Start: 2001, Stop: 2500}}},
}
for _, c := range cases {
got := metaBatches(c.total, c.size)
if len(got) != len(c.want) {
t.Fatalf("total=%d size=%d: got %d windows %v, want %d %v", c.total, c.size, len(got), got, len(c.want), c.want)
}
for i := range got {
if got[i] != c.want[i] {
t.Fatalf("total=%d size=%d window %d: got %+v want %+v", c.total, c.size, i, got[i], c.want[i])
}
}
}
}
// Every window must be within 1..total and the windows must be gap-free so no
// message is skipped or fetched twice.
func TestMetaBatchesCoverage(t *testing.T) {
const total, size = 4321, 1000
got := metaBatches(total, size)
if got[0].Start != 1 {
t.Fatalf("first window must start at 1, got %d", got[0].Start)
}
if last := got[len(got)-1]; last.Stop != total {
t.Fatalf("last window must stop at total=%d, got %d", total, last.Stop)
}
for i := 1; i < len(got); i++ {
if got[i].Start != got[i-1].Stop+1 {
t.Fatalf("gap/overlap between window %d (%+v) and %d (%+v)", i-1, got[i-1], i, got[i])
}
}
}