15 func _fl(depth int) string {
16 _, file, line, _ := runtime.Caller(depth + 1)
17 return fmt.Sprintf("[%s:%d]", filepath.Base(file), line)
20 func ok(t testing.TB, err error) {
22 t.Errorf("%s unexpected error: %v", _fl(1), err)
26 func readCodeLine(t testing.TB, conn *textproto.Conn, code int) string {
27 _, message, err := conn.ReadCodeLine(code)
29 t.Errorf("%s ReadCodeLine error: %v", _fl(1), err)
34 // runServer creates a TCP socket, runs a listening server, and returns the connection.
35 // The server exits when the Conn is closed.
36 func runServer(t *testing.T, server Server) net.Listener {
37 l, err := net.Listen("tcp", "localhost:0")
45 conn, err := l.Accept()
49 go AcceptConnection(conn, server)
56 type testServer struct {
61 func (s *testServer) Name() string {
65 func (s *testServer) VerifyAddress(addr mail.Address) ReplyLine {
66 for _, block := range s.blockList {
67 if block == addr.Address {
68 return ReplyBadMailbox
74 func createClient(t *testing.T, addr net.Addr) *textproto.Conn {
75 conn, err := textproto.Dial(addr.Network(), addr.String())
83 type requestResponse struct {
86 handler func(testing.TB, *textproto.Conn)
89 func runTableTest(t testing.TB, conn *textproto.Conn, seq []requestResponse) {
90 for i, rr := range seq {
91 t.Logf("%s case %d", _fl(1), i)
92 ok(t, conn.PrintfLine(rr.request))
93 if rr.handler != nil {
96 readCodeLine(t, conn, rr.responseCode)
102 func TestScenarioTypical(t *testing.T) {
104 blockList: []string{"Green@foo.com"},
106 l := runServer(t, &s)
109 conn := createClient(t, l.Addr())
111 message := readCodeLine(t, conn, 220)
112 if !strings.HasPrefix(message, s.Name()) {
113 t.Errorf("Greeting does not have server name, got %q", message)
116 greet := "greeting.TestScenarioTypical"
117 ok(t, conn.PrintfLine("EHLO "+greet))
119 _, message, err := conn.ReadResponse(250)
121 if !strings.Contains(message, greet) {
122 t.Errorf("EHLO response does not contain greeting, got %q", message)
125 ok(t, conn.PrintfLine("MAIL FROM:<Smith@bar.com>"))
126 readCodeLine(t, conn, 250)
128 ok(t, conn.PrintfLine("RCPT TO:<Jones@foo.com>"))
129 readCodeLine(t, conn, 250)
131 ok(t, conn.PrintfLine("RCPT TO:<Green@foo.com>"))
132 readCodeLine(t, conn, 550)
134 ok(t, conn.PrintfLine("RCPT TO:<Brown@foo.com>"))
135 readCodeLine(t, conn, 250)
137 ok(t, conn.PrintfLine("DATA"))
138 readCodeLine(t, conn, 354)
140 ok(t, conn.PrintfLine("Blah blah blah..."))
141 ok(t, conn.PrintfLine("...etc. etc. etc."))
142 ok(t, conn.PrintfLine("."))
143 readCodeLine(t, conn, 250)
145 ok(t, conn.PrintfLine("QUIT"))
146 readCodeLine(t, conn, 221)
149 func TestVerifyAddress(t *testing.T) {
151 blockList: []string{"banned@test.mail"},
153 l := runServer(t, &s)
156 conn := createClient(t, l.Addr())
157 readCodeLine(t, conn, 220)
159 runTableTest(t, conn, []requestResponse{
160 {"EHLO test", 0, func(t testing.TB, conn *textproto.Conn) { conn.ReadResponse(250) }},
161 {"VRFY banned@test.mail", 252, nil},
162 {"VRFY allowed@test.mail", 252, nil},
163 {"MAIL FROM:<sender@example.com>", 250, nil},
164 {"RCPT TO:<banned@test.mail>", 550, nil},
169 func TestCaseSensitivty(t *testing.T) {
174 conn := createClient(t, l.Addr())
175 readCodeLine(t, conn, 220)
177 runTableTest(t, conn, []requestResponse{
179 {"ehLO test.TEST", 0, func(t testing.TB, conn *textproto.Conn) { conn.ReadResponse(250) }},
180 {"mail FROM:<sender@example.com>", 250, nil},
181 {"RcPT tO:<receive@mail.com>", 250, nil},
182 {"DATa", 0, func(t testing.TB, conn *textproto.Conn) {
183 readCodeLine(t, conn, 354)
185 ok(t, conn.PrintfLine("."))
186 readCodeLine(t, conn, 250)
188 {"MAIL FR:", 501, nil},
193 func TestGetReceivedInfo(t *testing.T) {
195 server: &testServer{},
196 remoteAddr: &net.IPAddr{net.IPv4(127, 0, 0, 1), ""},
202 const line1 = "Received: from remote.test. (localhost [127.0.0.1])" + crlf
203 const line2 = "by Test-Server (mailpopbox) with "
204 const msgId = "abcdef.hijk"
205 lineLast := now.Format(time.RFC1123Z) + crlf
219 {params{"remote.test.", true, false, "foo@bar.com"},
221 line2 + "ESMTP id " + msgId + crlf,
222 "for <foo@bar.com>" + crlf,
223 "(using PLAINTEXT);" + crlf,
227 for _, test := range tests {
228 t.Logf("%#v", test.params)
230 conn.ehlo = test.params.ehlo
231 conn.esmtp = test.params.esmtp
232 conn.tls = test.params.tls
234 envelope := Envelope{
235 RcptTo: []mail.Address{{"", test.params.address}},
240 actual := conn.getReceivedInfo(envelope)
241 actualLines := strings.SplitAfter(string(actual), crlf)
243 if len(actualLines) != len(test.expect) {
244 t.Errorf("wrong numbber of lines, expected %d, got %d", len(test.expect), len(actualLines))
248 for i, line := range actualLines {
249 expect := test.expect[i]
250 if expect != strings.TrimLeft(line, " ") {
251 t.Errorf("Expected equal string %q, got %q", expect, line)