// TestRunOnce_AgainstRealTestMailboxWithRealisticVolume ist die // geforderte Pflichtprüfung 3: Test gegen Testpostfach mit realistischem // Nachrichtenaufkommen — echter IMAP4rev1-Wire-Protokoll-Lauf gegen den // echten ING-01-Server (mail/internal/imap), kein Fake. package imapimport import ( "context" "net" "testing" "gitea.perlbach24.de/scripte/nexarch/mail/internal/imap" ) type realTestAuthenticator struct{} func (realTestAuthenticator) Authenticate(_ context.Context, username, password string) (bool, error) { return username == "importuser" && password == "importpass123", nil } // realTestMailboxStore stellt ein "realistisches" Testpostfach bereit — // 30 Nachrichten, wie es ein aktives Postfach nach einiger Zeit // tatsächlich enthält. type realTestMailboxStore struct { uidvalidity uint64 messages []imap.Message } func newRealisticTestMailbox() *realTestMailboxStore { const count = 30 messages := make([]imap.Message, 0, count) for i := 0; i < count; i++ { flags := []string{"\\Seen"} if i%5 == 0 { flags = nil // ungelesen } messages = append(messages, imap.Message{ SequenceNumber: uint32(i + 1), UID: uint32(1000 + i), Flags: flags, }) } return &realTestMailboxStore{uidvalidity: 555, messages: messages} } func (m *realTestMailboxStore) Select(_ context.Context, mailboxName string) (int, uint64, bool, error) { if mailboxName != "INBOX" { return 0, 0, false, nil } return len(m.messages), m.uidvalidity, true, nil } func (m *realTestMailboxStore) Fetch(_ context.Context, _ string, seqNumbers []uint32) ([]imap.Message, error) { return m.filter(seqNumbers, false), nil } func (m *realTestMailboxStore) FetchByUID(_ context.Context, _ string, uids []uint32) ([]imap.Message, error) { return m.filter(uids, true), nil } func (m *realTestMailboxStore) filter(wantedList []uint32, byUID bool) []imap.Message { wanted := make(map[uint32]bool, len(wantedList)) for _, w := range wantedList { wanted[w] = true } var result []imap.Message for _, msg := range m.messages { key := msg.SequenceNumber if byUID { key = msg.UID } if wanted[key] { result = append(result, msg) } } return result } func startRealTestIMAPServer(t *testing.T) (addr string, stop func()) { t.Helper() srv := imap.NewServer(realTestAuthenticator{}, newRealisticTestMailbox()) listener, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("listener: %v", err) } ctx, cancel := context.WithCancel(context.Background()) done := make(chan struct{}) go func() { _ = srv.Serve(ctx, listener) close(done) }() return listener.Addr().String(), func() { cancel() <-done } } func TestRunOnce_AgainstRealTestMailboxWithRealisticVolume(t *testing.T) { store := setupStore(t) scheduler := NewScheduler(store) ctx := context.Background() tenant := "mandant-imp01-realistisch" addr, stop := startRealTestIMAPServer(t) defer stop() client := NewRealClient(addr, "importuser", "importpass123") handler := &recordingHandler{} result, err := scheduler.RunOnce(ctx, tenant, "INBOX", client, handler) if err != nil { t.Fatalf("runonce gegen echten server: %v", err) } if result.NewMessages != 30 { t.Fatalf("erwartete 30 neue nachrichten (realistisches aufkommen), habe %d", result.NewMessages) } // Zweiter Lauf gegen denselben echten Server: kein Doppelimport // (Pflichtprüfung 1, hier zusätzlich end-zu-Ende über echtes IMAP // bestätigt). handler2 := &recordingHandler{} result2, err := scheduler.RunOnce(ctx, tenant, "INBOX", client, handler2) if err != nil { t.Fatalf("zweiter lauf gegen echten server: %v", err) } if result2.NewMessages != 0 { t.Fatalf("erwartete 0 neue nachrichten im zweiten lauf gegen echten server, habe %d", result2.NewMessages) } if result2.ExistingMessages != 30 { t.Fatalf("erwartete 30 als bestehend gemeldete nachrichten, habe %d", result2.ExistingMessages) } }