Tweak the installation guide.
[mailpopbox.git] / pop3_test.go
1 // mailpopbox
2 // Copyright 2020 Blue Static <https://www.bluestatic.org>
3 // This program is free software licensed under the GNU General Public License,
4 // version 3.0. The full text of the license can be found in LICENSE.txt.
5 // SPDX-License-Identifier: GPL-3.0-only
6
7 package main
8
9 import (
10 "io/ioutil"
11 "net/textproto"
12 "os"
13 "path/filepath"
14 "testing"
15
16 "go.uber.org/zap"
17 )
18
19 func TestReset(t *testing.T) {
20 mbox := mailbox{
21 messages: []message{
22 {"msg1", 1, 4, false},
23 {"msg2", 2, 4, false},
24 },
25 }
26
27 msg := mbox.GetMessage(1)
28 if msg == nil {
29 t.Errorf("failed to GetMessage #1")
30 }
31
32 if msg.Deleted() {
33 t.Errorf("message %v should not be deleted", msg)
34 }
35
36 if err := mbox.Delete(msg); err != nil {
37 t.Error(err)
38 }
39
40 if !msg.Deleted() {
41 t.Errorf("message %v should be deleted", msg)
42 }
43
44 mbox.Reset()
45
46 if msg.Deleted() {
47 t.Errorf("reset did not un-delete message %v", msg)
48 }
49 }
50
51 func TestOpenMailboxAuth(t *testing.T) {
52 dir, err := ioutil.TempDir("", "maildrop")
53 if err != nil {
54 t.Errorf("Failed to create temp dir: %v", err)
55 return
56 }
57 defer os.RemoveAll(dir)
58
59 s := &pop3Server{
60 config: Config{
61 Servers: []Server{
62 {
63 Domain: "example.com",
64 MailboxPassword: "letmein",
65 MaildropPath: dir,
66 },
67 {
68 Domain: "test.net",
69 MailboxPassword: "open-sesame",
70 MaildropPath: dir,
71 },
72 },
73 },
74 log: zap.NewNop(),
75 }
76
77 cases := []struct {
78 user, pass string
79 ok bool
80 }{
81 {"mailbox@example.com", "letmein", true},
82 {"mailbox@test.net", "open-sesame", true},
83 {"mailbox@example.com", "open-sesame", false},
84 {"test@test.net", "open-sesame", false},
85 {"mailbox@an-example.net", "letmein", false},
86 }
87 for i, c := range cases {
88 mb, err := s.OpenMailbox(c.user, c.pass)
89 got := (mb != nil && err == nil)
90 if got != c.ok {
91 t.Errorf("Expected error=%v for case %d (%#v), got %v (error=%v, mb=%v)", c.ok, i, c, got, err, mb)
92 }
93 }
94 }
95
96 func TestBasicListener(t *testing.T) {
97 dir, err := ioutil.TempDir("", "maildrop")
98 if err != nil {
99 t.Errorf("Failed to create temp dir: %v", err)
100 return
101 }
102 defer os.RemoveAll(dir)
103
104 s := &pop3Server{
105 config: Config{
106 POP3Port: 9648,
107 Hostname: "example.com",
108 Servers: []Server{
109 {
110 Domain: "example.com",
111 MaildropPath: dir,
112 },
113 },
114 },
115 log: zap.NewNop(),
116 }
117
118 go s.run()
119
120 conn, err := textproto.Dial("tcp", "localhost:9648")
121 if err != nil {
122 t.Errorf("Failed to dial test server: %v", err)
123 return
124 }
125
126 _, err = conn.ReadLine()
127 if err != nil {
128 t.Errorf("Failed to read line: %v", err)
129 return
130 }
131 }
132
133 func TestMailbox(t *testing.T) {
134 dir, err := ioutil.TempDir("", "maildrop")
135 if err != nil {
136 t.Errorf("Failed to create temp dir: %v", err)
137 return
138 }
139 defer os.RemoveAll(dir)
140
141 // Create the first message.
142 f, err := os.Create(filepath.Join(dir, "a.msg"))
143 if err != nil {
144 t.Errorf("Failed to create a.msg: %v", err)
145 return
146 }
147 for i := 0; i < 1024*10; i++ {
148 buf := []byte{'a'}
149 _, err = f.Write(buf)
150 if err != nil {
151 t.Errorf("Failed to write a.msg: %v", err)
152 }
153 }
154 f.Close()
155
156 // Create the second message.
157 f, err = os.Create(filepath.Join(dir, "b.msg"))
158 if err != nil {
159 t.Errorf("Failed to create b.msg: %v", err)
160 return
161 }
162 for i := 0; i < 1024*3; i++ {
163 buf := []byte{'z'}
164 _, err = f.Write(buf)
165 if err != nil {
166 t.Errorf("Failed to write z.msg: %v", err)
167 }
168 }
169 f.Close()
170
171 s := &pop3Server{
172 config: Config{
173 Servers: []Server{
174 {
175 Domain: "example.com",
176 MailboxPassword: "letmein",
177 MaildropPath: dir,
178 },
179 },
180 },
181 log: zap.NewNop(),
182 }
183
184 // Test message metadata.
185 mb, err := s.OpenMailbox("mailbox@example.com", "letmein")
186 if err != nil {
187 t.Errorf("Failed to open mailbox: %v", err)
188 }
189
190 msgs, err := mb.ListMessages()
191 if err != nil {
192 t.Errorf("Failed to list messages: %v", err)
193 }
194
195 if want, got := 2, len(msgs); want != got {
196 t.Errorf("Want %d messages, got %d", want, got)
197 }
198
199 if mb.GetMessage(0) != nil {
200 t.Errorf("Messages should be 1-indexed")
201 }
202 if mb.GetMessage(3) != nil {
203 t.Errorf("Retreived unexpected message")
204 }
205
206 if msgs[0] != mb.GetMessage(msgs[0].ID()) {
207 t.Errorf("Failed to look up message by ID")
208 }
209
210 if want, got := "a", msgs[0].UniqueID(); want != got {
211 t.Errorf("Want message #1 unique ID to be %s, got %s", want, got)
212 }
213 if want, got := 1024*10, msgs[0].Size(); want != got {
214 t.Errorf("Want message #1 size to be %v, got %v", want, got)
215 }
216
217 if want, got := "b", msgs[1].UniqueID(); want != got {
218 t.Errorf("Want message #2 unique ID to be %s, got %s", want, got)
219 }
220 if want, got := 1024*3, msgs[1].Size(); want != got {
221 t.Errorf("Want message #2 size to be %v, got %v", want, got)
222 }
223
224 // Test message contents.
225 rc, err := mb.Retrieve(msgs[0])
226 if err != nil {
227 t.Errorf("Failed to retrieve message: %v", err)
228 }
229 rc.Close()
230
231 // Test deletion marking and reset.
232 err = mb.Delete(msgs[1])
233 if err != nil {
234 t.Errorf("Failed to mark message #2 for deletion: %v", err)
235 }
236
237 if !msgs[1].Deleted() {
238 t.Errorf("Message should be marked for deletion and isn't")
239 }
240
241 mb.Reset()
242
243 if msgs[1].Deleted() {
244 t.Errorf("Message is marked for deletion and shouldn't be")
245 }
246
247 // Test deletion for real.
248 err = mb.Delete(msgs[0])
249 if err != nil {
250 t.Errorf("Failed to mark message for deletion: %v", err)
251 }
252
253 err = mb.Close()
254 if err != nil {
255 t.Errorf("Failed to close mailbox: %v", err)
256 }
257
258 mb, err = s.OpenMailbox("mailbox@example.com", "letmein")
259 if err != nil {
260 t.Errorf("Failed to re-open mailbox: %v", err)
261 }
262
263 msgs, err = mb.ListMessages()
264 if err != nil {
265 t.Errorf("Failed to list messages: %v", err)
266 }
267
268 if want, got := 1, len(msgs); want != got {
269 t.Errorf("Number of messages should be %d, got %d", want, got)
270 }
271
272 if want, got := "b", msgs[0].UniqueID(); want != got {
273 t.Errorf("Message Unique ID should be %s, got %s", want, got)
274 }
275 }