-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathforward_test.go
More file actions
144 lines (131 loc) · 4.16 KB
/
Copy pathforward_test.go
File metadata and controls
144 lines (131 loc) · 4.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package main
import (
"bytes"
"net"
"strings"
"testing"
"time"
"github.com/emersion/go-imap/backend/memory"
"github.com/emersion/go-imap/client"
"github.com/emersion/go-imap/server"
)
// startMemoryServer spins up an in-memory IMAP server (no TLS) on a random
// local port and returns its address.
func startMemoryServer(t *testing.T) string {
t.Helper()
be := memory.New()
s := server.New(be)
s.AllowInsecureAuth = true
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("listen: %v", err)
}
go func() { _ = s.Serve(ln) }()
t.Cleanup(func() { _ = s.Close() })
return ln.Addr().String()
}
func dialTest(t *testing.T, addr string) *client.Client {
t.Helper()
c, err := client.Dial(addr) // plaintext for the test server
if err != nil {
t.Fatalf("dial: %v", err)
}
if err := c.Login("username", "password"); err != nil { // memory backend defaults
t.Fatalf("login: %v", err)
}
if _, err := c.Select("INBOX", false); err != nil {
t.Fatalf("select: %v", err)
}
t.Cleanup(func() { _ = c.Logout() })
return c
}
func findMarker(msgs []fetchedMessage, marker string) *fetchedMessage {
for i := range msgs {
if bytes.Contains(msgs[i].raw, []byte(marker)) {
return &msgs[i]
}
}
return nil
}
// TestFetchUnseenAndMarkSeen verifies the three core IMAP guarantees:
// 1. fetchUnseen returns the full raw body of an unseen message,
// 2. fetching uses PEEK so the message stays UNSEEN afterwards,
// 3. markSeen removes it from the UNSEEN set.
func TestFetchUnseenAndMarkSeen(t *testing.T) {
addr := startMemoryServer(t)
c := dialTest(t, addr)
const marker = "X-Imap2gmail-Test: nonce-9f3a"
raw := "From: sender@example.com\r\n" +
"To: dest@example.com\r\n" +
"Subject: hello world\r\n" +
marker + "\r\n\r\n" +
"this is the body\r\n"
if err := c.Append("INBOX", nil, time.Time{}, strings.NewReader(raw)); err != nil {
t.Fatalf("append: %v", err)
}
msgs, err := fetchUnseen(c)
if err != nil {
t.Fatalf("fetchUnseen: %v", err)
}
got := findMarker(msgs, marker)
if got == nil {
t.Fatalf("appended message not found among %d unseen messages", len(msgs))
}
if !bytes.Contains(got.raw, []byte("this is the body")) {
t.Fatalf("fetched body does not contain expected content: %q", got.raw)
}
// PEEK: message must still be UNSEEN after fetching.
again, err := fetchUnseen(c)
if err != nil {
t.Fatalf("second fetchUnseen: %v", err)
}
if findMarker(again, marker) == nil {
t.Fatal("message disappeared from UNSEEN after fetch — PEEK failed (it set \\Seen)")
}
// markSeen must remove it from UNSEEN.
if err := markSeen(c, got.seqNum); err != nil {
t.Fatalf("markSeen: %v", err)
}
after, err := fetchUnseen(c)
if err != nil {
t.Fatalf("post-markSeen fetchUnseen: %v", err)
}
if findMarker(after, marker) != nil {
t.Fatal("message still UNSEEN after markSeen")
}
}
func TestParseConfigMultiAccount(t *testing.T) {
raw := `{
"accounts": [
{"name":"o2","imap":{"host":"poczta.o2.pl","user":"a@o2.pl","password":"p"},
"gmail":{"token":{"client_id":"c","client_secret":"s","refresh_token":"r"}}},
{"imap":{"host":"imap.wp.pl","port":993,"user":"b@wp.pl","password":"p2"},
"gmail":{"user":"me","token":{"client_id":"c","client_secret":"s","refresh_token":"r"}}}
]}`
cfg, err := parseConfig([]byte(raw))
if err != nil {
t.Fatalf("parseConfig: %v", err)
}
if len(cfg.Accounts) != 2 {
t.Fatalf("want 2 accounts, got %d", len(cfg.Accounts))
}
// Defaults applied.
if cfg.Accounts[0].IMAP.Port != 993 {
t.Errorf("default port not applied: %d", cfg.Accounts[0].IMAP.Port)
}
if cfg.Accounts[0].IMAP.Mailbox != "INBOX" {
t.Errorf("default mailbox not applied: %q", cfg.Accounts[0].IMAP.Mailbox)
}
if cfg.Accounts[1].Name != "imap.wp.pl" {
t.Errorf("default name not derived from host: %q", cfg.Accounts[1].Name)
}
if !cfg.Accounts[0].markSeen() {
t.Error("markSeen should default to true")
}
}
func TestParseConfigRejectsIncomplete(t *testing.T) {
raw := `{"accounts":[{"name":"x","imap":{"host":"h","user":"u","password":"p"},"gmail":{"token":{"client_id":"c"}}}]}`
if _, err := parseConfig([]byte(raw)); err == nil {
t.Fatal("expected error for incomplete gmail token, got nil")
}
}