14 func _fl(depth int) string {
15 _, file, line, _ := runtime.Caller(depth + 1)
16 return fmt.Sprintf("[%s:%d]", filepath.Base(file), line)
19 func ok(t testing.TB, err error) {
21 t.Errorf("%s unexpected error: %v", _fl(1), err)
25 func readCodeLine(t testing.TB, conn *textproto.Conn, code int) string {
26 _, message, err := conn.ReadCodeLine(code)
28 t.Errorf("%s ReadCodeLine error: %v", _fl(1), err)
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")
44 conn, err := l.Accept()
48 go AcceptConnection(conn, server)
55 type testServer struct {
60 func (s *testServer) Name() string {
64 func (s *testServer) VerifyAddress(addr mail.Address) ReplyLine {
65 for _, block := range s.blockList {
66 if block == addr.Address {
67 return ReplyBadMailbox
73 func createClient(t *testing.T, addr net.Addr) *textproto.Conn {
74 conn, err := textproto.Dial(addr.Network(), addr.String())
82 type requestResponse struct {
85 handler func(testing.TB, *textproto.Conn)
88 func runTableTest(t testing.TB, conn *textproto.Conn, seq []requestResponse) {
89 for i, rr := range seq {
90 t.Logf("%s case %d", _fl(1), i)
91 ok(t, conn.PrintfLine(rr.request))
92 if rr.handler != nil {
95 readCodeLine(t, conn, rr.responseCode)
101 func TestScenarioTypical(t *testing.T) {
103 blockList: []string{"Green@foo.com"},
105 l := runServer(t, &s)
108 conn := createClient(t, l.Addr())
110 message := readCodeLine(t, conn, 220)
111 if !strings.HasPrefix(message, s.Name()) {
112 t.Errorf("Greeting does not have server name, got %q", message)
115 greet := "greeting.TestScenarioTypical"
116 ok(t, conn.PrintfLine("EHLO "+greet))
118 _, message, err := conn.ReadResponse(250)
120 if !strings.Contains(message, greet) {
121 t.Errorf("EHLO response does not contain greeting, got %q", message)
124 ok(t, conn.PrintfLine("MAIL FROM:<Smith@bar.com>"))
125 readCodeLine(t, conn, 250)
127 ok(t, conn.PrintfLine("RCPT TO:<Jones@foo.com>"))
128 readCodeLine(t, conn, 250)
130 ok(t, conn.PrintfLine("RCPT TO:<Green@foo.com>"))
131 readCodeLine(t, conn, 550)
133 ok(t, conn.PrintfLine("RCPT TO:<Brown@foo.com>"))
134 readCodeLine(t, conn, 250)
136 ok(t, conn.PrintfLine("DATA"))
137 readCodeLine(t, conn, 354)
139 ok(t, conn.PrintfLine("Blah blah blah..."))
140 ok(t, conn.PrintfLine("...etc. etc. etc."))
141 ok(t, conn.PrintfLine("."))
142 readCodeLine(t, conn, 250)
144 ok(t, conn.PrintfLine("QUIT"))
145 readCodeLine(t, conn, 221)
148 func TestVerifyAddress(t *testing.T) {
150 blockList: []string{"banned@test.mail"},
152 l := runServer(t, &s)
155 conn := createClient(t, l.Addr())
156 readCodeLine(t, conn, 220)
158 runTableTest(t, conn, []requestResponse{
159 {"EHLO test", 0, func(t testing.TB, conn *textproto.Conn) { conn.ReadResponse(250) }},
160 {"VRFY banned@test.mail", 252, nil},
161 {"VRFY allowed@test.mail", 252, nil},
162 {"MAIL FROM:<sender@example.com>", 250, nil},
163 {"RCPT TO:<banned@test.mail>", 550, nil},