Complete the unittest by adding smtp.Server.VerifyAddress.
[mailpopbox.git] / smtp / conn_test.go
1 package smtp
2
3 import (
4 "fmt"
5 "net"
6 "net/mail"
7 "net/textproto"
8 "path/filepath"
9 "runtime"
10 "strings"
11 "testing"
12 )
13
14 func _fl(depth int) string {
15 _, file, line, _ := runtime.Caller(depth + 1)
16 return fmt.Sprintf("[%s:%d]", filepath.Base(file), line)
17 }
18
19 func ok(t testing.TB, err error) {
20 if err != nil {
21 t.Errorf("%s unexpected error: %v", _fl(1), err)
22 }
23 }
24
25 func readCodeLine(t testing.TB, conn *textproto.Conn, code int) string {
26 _, message, err := conn.ReadCodeLine(code)
27 if err != nil {
28 t.Errorf("%s ReadCodeLine error: %v", _fl(1), err)
29 }
30 return message
31 }
32
33 // runServer creates a TCP socket, runs a listening server, and returns the connection.
34 // The server exits when the Conn is closed.
35 func runServer(t *testing.T, server Server) net.Listener {
36 l, err := net.Listen("tcp", "localhost:0")
37 if err != nil {
38 t.Fatal(err)
39 return nil
40 }
41
42 go func() {
43 for {
44 conn, err := l.Accept()
45 if err != nil {
46 return
47 }
48 go AcceptConnection(conn, server)
49 }
50 }()
51
52 return l
53 }
54
55 type testServer struct {
56 EmptyServerCallbacks
57 blockList []string
58 }
59
60 func (s *testServer) Name() string {
61 return "Test-Server"
62 }
63
64 func (s *testServer) VerifyAddress(addr mail.Address) ReplyLine {
65 for _, block := range s.blockList {
66 if block == addr.Address {
67 return ReplyBadMailbox
68 }
69 }
70 return ReplyOK
71 }
72
73 func createClient(t *testing.T, addr net.Addr) *textproto.Conn {
74 conn, err := textproto.Dial(addr.Network(), addr.String())
75 if err != nil {
76 t.Fatal(err)
77 return nil
78 }
79 return conn
80 }
81
82 // RFC 5321 ยง D.1
83 func TestScenarioTypical(t *testing.T) {
84 s := testServer{
85 blockList: []string{"Green@foo.com"},
86 }
87 l := runServer(t, &s)
88 defer l.Close()
89
90 conn := createClient(t, l.Addr())
91
92 message := readCodeLine(t, conn, 220)
93 if !strings.HasPrefix(message, s.Name()) {
94 t.Errorf("Greeting does not have server name, got %q", message)
95 }
96
97 greet := "greeting.TestScenarioTypical"
98 ok(t, conn.PrintfLine("EHLO "+greet))
99
100 _, message, err := conn.ReadResponse(250)
101 ok(t, err)
102 if !strings.Contains(message, greet) {
103 t.Errorf("EHLO response does not contain greeting, got %q", message)
104 }
105
106 ok(t, conn.PrintfLine("MAIL FROM:<Smith@bar.com>"))
107 readCodeLine(t, conn, 250)
108
109 ok(t, conn.PrintfLine("RCPT TO:<Jones@foo.com>"))
110 readCodeLine(t, conn, 250)
111
112 ok(t, conn.PrintfLine("RCPT TO:<Green@foo.com>"))
113 readCodeLine(t, conn, 550)
114
115 ok(t, conn.PrintfLine("RCPT TO:<Brown@foo.com>"))
116 readCodeLine(t, conn, 250)
117
118 ok(t, conn.PrintfLine("DATA"))
119 readCodeLine(t, conn, 354)
120
121 ok(t, conn.PrintfLine("Blah blah blah..."))
122 ok(t, conn.PrintfLine("...etc. etc. etc."))
123 ok(t, conn.PrintfLine("."))
124 readCodeLine(t, conn, 250)
125
126 ok(t, conn.PrintfLine("QUIT"))
127 readCodeLine(t, conn, 221)
128 }