]>
src.bluestatic.org Git - mailpopbox.git/blob - pop3/conn_test.go
16 "github.com/uber-go/zap"
19 func _fl(depth
int) string {
20 _
, file
, line
, _
:= runtime
.Caller(depth
+ 1)
21 return fmt
.Sprintf("[%s:%d]", filepath
.Base(file
), line
)
24 func ok(t testing
.TB
, err error
) {
26 t
.Errorf("%s unexpected error: %v", _fl(1), err
)
30 func responseOK(t testing
.TB
, conn
*textproto
.Conn
) string {
31 line
, err
:= conn
.ReadLine()
33 t
.Errorf("%s responseOK: %v", _fl(1), err
)
35 if !strings
.HasPrefix(line
, "+OK") {
36 t
.Errorf("%s expected +OK, got %q", _fl(1), line
)
41 func responseERR(t testing
.TB
, conn
*textproto
.Conn
) string {
42 line
, err
:= conn
.ReadLine()
44 t
.Errorf("%s responseERR: %v", _fl(1), err
)
46 if !strings
.HasPrefix(line
, "-ERR") {
47 t
.Errorf("%s expected -ERR, got %q", _fl(1), line
)
52 func runServer(t
*testing
.T
, po PostOffice
) net
.Listener
{
53 l
, err
:= net
.Listen("tcp", "localhost:0")
61 conn
, err
:= l
.Accept()
65 go AcceptConnection(conn
, po
, zap
.New(zap
.NullEncoder()))
71 type testServer
struct {
76 func (s
*testServer
) Name() string {
80 func (s
*testServer
) OpenMailbox(user
, pass
string) (Mailbox
, error
) {
81 if s
.user
== user
&& s
.pass
== pass
{
84 return nil, fmt
.Errorf("bad username/pass")
87 type testMailbox
struct {
88 msgs
map[int]*testMessage
91 type MessageList
[]Message
93 func (l MessageList
) Len() int {
96 func (l MessageList
) Less(i
, j
int) bool {
97 return l
[i
].ID() < l
[j
].ID()
99 func (l MessageList
) Swap(i
, j
int) {
100 l
[i
], l
[j
] = l
[j
], l
[i
]
103 func (mb
*testMailbox
) ListMessages() ([]Message
, error
) {
104 msgs
:= make([]Message
, 0, len(mb
.msgs
))
105 for i
, _
:= range mb
.msgs
{
106 msgs
= append(msgs
, mb
.msgs
[i
])
108 sort
.Sort(MessageList(msgs
))
112 func (mb
*testMailbox
) GetMessage(id
int) Message
{
113 if msg
, ok
:= mb
.msgs
[id
]; ok
{
119 func (mb
*testMailbox
) Retrieve(msg Message
) (io
.ReadCloser
, error
) {
120 r
:= strings
.NewReader(msg
.(*testMessage
).body
)
121 return ioutil
.NopCloser(r
), nil
124 func (mb
*testMailbox
) Delete(msg Message
) error
{
125 msg
.(*testMessage
).deleted
= true
129 func (mb
*testMailbox
) Close() error
{
133 func (mb
*testMailbox
) Reset() {
134 for _
, msg
:= range mb
.msgs
{
139 type testMessage
struct {
146 func (m
*testMessage
) UniqueID() string {
147 return fmt
.Sprintf("%p", m
)
150 func (m
*testMessage
) ID() int {
153 func (m
*testMessage
) Size() int {
156 func (m
*testMessage
) Deleted() bool {
160 func newTestServer() *testServer
{
165 msgs
: make(map[int]*testMessage
),
171 func TestExampleSession(t
*testing
.T
) {
176 s
.mb
.msgs
[1] = &testMessage
{1, 120, false, ""}
177 s
.mb
.msgs
[2] = &testMessage
{2, 200, false, ""}
179 conn
, err
:= textproto
.Dial(l
.Addr().Network(), l
.Addr().String())
182 line
:= responseOK(t
, conn
)
183 if !strings
.Contains(line
, s
.Name()) {
184 t
.Errorf("POP greeting did not include server name, got %q", line
)
187 ok(t
, conn
.PrintfLine("USER u"))
190 ok(t
, conn
.PrintfLine("PASS p"))
193 ok(t
, conn
.PrintfLine("STAT"))
194 line
= responseOK(t
, conn
)
195 expected
:= "+OK 2 320"
196 if line
!= expected
{
197 t
.Errorf("STAT expected %q, got %q", expected
, line
)
200 ok(t
, conn
.PrintfLine("LIST"))
202 lines
, err
:= conn
.ReadDotLines()
205 t
.Errorf("LIST expected 2 lines, got %d", len(lines
))
208 if lines
[0] != expected
{
209 t
.Errorf("LIST line 0 expected %q, got %q", expected
, lines
[0])
212 if lines
[1] != expected
{
213 t
.Errorf("LIST line 1 expected %q, got %q", expected
, lines
[1])
216 ok(t
, conn
.PrintfLine("QUIT"))
220 type requestResponse
struct {
222 expecter
func(testing
.TB
, *textproto
.Conn
) string
225 func expectOKResponse(predicate
func(string) bool) func(testing
.TB
, *textproto
.Conn
) string {
226 return func(t testing
.TB
, conn
*textproto
.Conn
) string {
227 line
:= responseOK(t
, conn
)
228 if !predicate(line
) {
229 t
.Errorf("%s Predicate failed, got %q", _fl(1), line
)
235 func clientServerTest(t
*testing
.T
, s
*testServer
, sequence
[]requestResponse
) {
239 conn
, err
:= textproto
.Dial(l
.Addr().Network(), l
.Addr().String())
244 for _
, pair
:= range sequence
{
245 ok(t
, conn
.PrintfLine(pair
.command
))
246 pair
.expecter(t
, conn
)
248 t
.Logf("command %q", pair
.command
)
253 func TestAuthStates(t
*testing
.T
) {
254 clientServerTest(t
, newTestServer(), []requestResponse
{
255 {"STAT", responseERR
},
256 {"NOOP", responseOK
},
257 {"USER bad", responseOK
},
258 {"PASS bad", responseERR
},
259 {"USER", responseERR
},
260 {"USER x", responseOK
},
261 {"PASS", responseERR
},
262 {"LIST", responseERR
},
263 {"USER u", responseOK
},
264 {"PASS bad", responseERR
},
265 {"STAT", responseERR
},
266 {"PASS p", responseOK
},
267 {"QUIT", responseOK
},
271 func TestDeleted(t
*testing
.T
) {
273 s
.mb
.msgs
[1] = &testMessage
{1, 999, false, ""}
274 s
.mb
.msgs
[2] = &testMessage
{2, 10, false, ""}
276 clientServerTest(t
, s
, []requestResponse
{
277 {"USER u", responseOK
},
278 {"PASS p", responseOK
},
279 {"STAT", expectOKResponse(func(s
string) bool {
280 return s
== "+OK 2 1009"
282 {"DELE 1", responseOK
},
283 {"RETR 1", responseERR
},
284 {"DELE 1", responseERR
},
285 {"STAT", expectOKResponse(func(s
string) bool {
286 return s
== "+OK 1 10"
288 {"RSET", responseOK
},
289 {"STAT", expectOKResponse(func(s
string) bool {
290 return s
== "+OK 2 1009"
292 {"QUIT", responseOK
},
296 func TestCaseSensitivty(t
*testing
.T
) {
298 s
.mb
.msgs
[999] = &testMessage
{999, 1, false, "a"}
300 clientServerTest(t
, s
, []requestResponse
{
301 {"user u", responseOK
},
302 {"PasS p", responseOK
},
303 {"sTaT", responseOK
},
304 {"retr 1", responseERR
},
305 {"dele 999", responseOK
},
306 {"QUIT", responseOK
},
310 func TestRetr(t
*testing
.T
) {
312 s
.mb
.msgs
[1] = &testMessage
{1, 5, false, "hello"}
313 s
.mb
.msgs
[2] = &testMessage
{2, 69, false, "this\r\nis a\r\n.\r\ntest"}
315 clientServerTest(t
, s
, []requestResponse
{
316 {"USER u", responseOK
},
317 {"PASS p", responseOK
},
318 {"STAT", responseOK
},
319 {"RETR 1", func(t testing
.TB
, tp
*textproto
.Conn
) string {
325 resp
, err
:= tp
.ReadDotLines()
331 expected
:= []string{"hello"}
332 if !reflect
.DeepEqual(resp
, expected
) {
333 t
.Errorf("Expected %v, got %v", expected
, resp
)
338 {"RETR 2", func(t testing
.TB
, tp
*textproto
.Conn
) string {
344 resp
, err
:= tp
.ReadDotLines()
350 expected
:= []string{"this", "is a", ".", "test"}
351 if !reflect
.DeepEqual(resp
, expected
) {
352 t
.Errorf("Expected %v, got %v", expected
, resp
)
357 {"QUIT", responseOK
},
361 func TestUidl(t
*testing
.T
) {
363 s
.mb
.msgs
[1] = &testMessage
{1, 3, false, "abc"}
364 s
.mb
.msgs
[2] = &testMessage
{2, 1, true, "Z"}
365 s
.mb
.msgs
[3] = &testMessage
{3, 4, false, "test"}
367 clientServerTest(t
, s
, []requestResponse
{
368 {"USER u", responseOK
},
369 {"PASS p", responseOK
},
370 {"UIDL", func(t testing
.TB
, tp
*textproto
.Conn
) string {
376 resp
, err
:= tp
.ReadDotLines()
382 expected
:= []string{
383 fmt
.Sprintf("1 %p", s
.mb
.msgs
[1]),
384 fmt
.Sprintf("3 %p", s
.mb
.msgs
[3]),
386 if !reflect
.DeepEqual(resp
, expected
) {
387 t
.Errorf("Expected %v, got %v", expected
, resp
)
392 {"QUIT", responseOK
},
396 func TestDele(t
*testing
.T
) {
398 s
.mb
.msgs
[1] = &testMessage
{1, 3, false, "abc"}
399 s
.mb
.msgs
[2] = &testMessage
{2, 1, false, "d"}
401 clientServerTest(t
, s
, []requestResponse
{
402 {"USER u", responseOK
},
403 {"PASS p", responseOK
},
404 {"STAT", expectOKResponse(func(s
string) bool {
405 return s
== "+OK 2 4"
407 {"DELE 1", responseOK
},
408 {"STAT", expectOKResponse(func(s
string) bool {
409 return s
== "+OK 1 1"
411 {"RSET", responseOK
},
412 {"STAT", expectOKResponse(func(s
string) bool {
413 return s
== "+OK 2 4"
415 {"QUIT", responseOK
},
418 if s
.mb
.msgs
[1].Deleted() || s
.mb
.msgs
[2].Deleted() {
419 t
.Errorf("RSET should not delete a message")
422 clientServerTest(t
, s
, []requestResponse
{
423 {"USER u", responseOK
},
424 {"PASS p", responseOK
},
425 {"STAT", expectOKResponse(func(s
string) bool {
426 return s
== "+OK 2 4"
428 {"DELE 1", responseOK
},
429 {"STAT", expectOKResponse(func(s
string) bool {
430 return s
== "+OK 1 1"
432 {"QUIT", responseOK
},
435 if !s
.mb
.msgs
[1].Deleted() {
436 t
.Errorf("DELE did not work")
438 if s
.mb
.msgs
[2].Deleted() {
439 t
.Errorf("DELE the wrong message")
443 func TestCapa(t
*testing
.T
) {
446 capaTest
:= func(t testing
.TB
, tp
*textproto
.Conn
) string {
452 resp
, err
:= tp
.ReadDotLines()
464 caps
:= map[string]int{
468 for _
, line
:= range resp
{
469 if val
, ok
:= caps
[line
]; ok
{
470 if val
== capNeeded
{
473 t
.Errorf("unxpected capa value %q", line
)
479 for c
, val
:= range caps
{
481 t
.Errorf("unexpected capa value for %q: %d", c
, val
)
487 clientServerTest(t
, s
, []requestResponse
{
489 {"USER u", responseOK
},
491 {"PASS p", responseOK
},
493 {"QUIT", responseOK
},