From cb5e79debb1ce0ff8474f2de7220bb21ba082b21 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Sun, 23 Nov 2014 12:43:33 +0000 Subject: [PATCH] Add session tests --- mailhog/config/config.go | 3 +- mailhog/smtp/server/session.go | 31 ++++++---- mailhog/smtp/server/session_test.go | 96 +++++++++++++++++++++++++++++ main.go | 11 +++- 4 files changed, 125 insertions(+), 16 deletions(-) diff --git a/mailhog/config/config.go b/mailhog/config/config.go index 51401a3..1ac4c3d 100644 --- a/mailhog/config/config.go +++ b/mailhog/config/config.go @@ -1,6 +1,7 @@ package config import ( + "github.com/ian-kent/Go-MailHog/mailhog/data" "github.com/ian-kent/Go-MailHog/mailhog/storage" ) @@ -22,7 +23,7 @@ type Config struct { MongoUri string MongoDb string MongoColl string - MessageChan chan interface{} + MessageChan chan *data.Message Storage storage.Storage Assets func(asset string) ([]byte, error) } diff --git a/mailhog/smtp/server/session.go b/mailhog/smtp/server/session.go index 51d263d..93fbf1a 100644 --- a/mailhog/smtp/server/session.go +++ b/mailhog/smtp/server/session.go @@ -7,26 +7,27 @@ import ( "log" "strings" - "github.com/ian-kent/Go-MailHog/mailhog/config" "github.com/ian-kent/Go-MailHog/mailhog/data" "github.com/ian-kent/Go-MailHog/mailhog/smtp/protocol" + "github.com/ian-kent/Go-MailHog/mailhog/storage" ) // Session represents a SMTP session using net.TCPConn type Session struct { conn io.ReadWriteCloser proto *protocol.Protocol - conf *config.Config + storage storage.Storage + messageChan chan *data.Message remoteAddress string isTLS bool line string } // Accept starts a new SMTP session using io.ReadWriteCloser -func Accept(remoteAddress string, conn io.ReadWriteCloser, conf *config.Config) { +func Accept(remoteAddress string, conn io.ReadWriteCloser, storage storage.Storage, messageChan chan *data.Message, hostname string) { proto := protocol.NewProtocol() - proto.Hostname = conf.Hostname - session := &Session{conn, proto, conf, remoteAddress, false, ""} + proto.Hostname = hostname + session := &Session{conn, proto, storage, messageChan, remoteAddress, false, ""} proto.LogHandler = session.logf proto.MessageReceivedHandler = session.acceptMessage proto.ValidateSenderHandler = session.validateSender @@ -54,8 +55,8 @@ func (c *Session) validateSender(from string) bool { func (c *Session) acceptMessage(msg *data.Message) (id string, err error) { c.logf("Storing message %s", msg.ID) - id, err = c.conf.Storage.Store(msg) - c.conf.MessageChan <- msg + id, err = c.storage.Store(msg) + c.messageChan <- msg return } @@ -72,8 +73,10 @@ func (c *Session) Read() bool { if n == 0 { c.logf("Connection closed by remote host\n") + io.Closer(c.conn).Close() // not sure this is necessary? return false } + if err != nil { c.logf("Error reading from socket: %s\n", err) return false @@ -86,13 +89,15 @@ func (c *Session) Read() bool { c.line += text - line, reply := c.proto.Parse(c.line) - c.line = line + for strings.Contains(c.line, "\n") { + line, reply := c.proto.Parse(c.line) + c.line = line - if reply != nil { - c.Write(reply) - if reply.Status == 221 { - io.Closer(c.conn).Close() + if reply != nil { + c.Write(reply) + if reply.Status == 221 { + io.Closer(c.conn).Close() + } } } diff --git a/mailhog/smtp/server/session_test.go b/mailhog/smtp/server/session_test.go index 2b9673d..e24edda 100644 --- a/mailhog/smtp/server/session_test.go +++ b/mailhog/smtp/server/session_test.go @@ -1,11 +1,107 @@ package server import ( + "errors" + "sync" "testing" . "github.com/smartystreets/goconvey/convey" + + "github.com/ian-kent/Go-MailHog/mailhog/data" + "github.com/ian-kent/Go-MailHog/mailhog/storage" ) +type fakeRw struct { + _read func(p []byte) (n int, err error) + _write func(p []byte) (n int, err error) + _close func() error +} + +func (rw *fakeRw) Read(p []byte) (n int, err error) { + if rw._read != nil { + return rw._read(p) + } + return 0, nil +} +func (rw *fakeRw) Close() error { + if rw._close != nil { + return rw._close() + } + return nil +} +func (rw *fakeRw) Write(p []byte) (n int, err error) { + if rw._write != nil { + return rw._write(p) + } + return len(p), nil +} + +func TestAccept(t *testing.T) { + Convey("Accept should handle a connection", t, func() { + frw := &fakeRw{} + mChan := make(chan *data.Message) + Accept("1.1.1.1:11111", frw, storage.CreateInMemory(), mChan, "localhost") + }) +} + +func TestSocketError(t *testing.T) { + Convey("Socket errors should return from Accept", t, func() { + frw := &fakeRw{ + _read: func(p []byte) (n int, err error) { + return -1, errors.New("OINK") + }, + } + mChan := make(chan *data.Message) + Accept("1.1.1.1:11111", frw, storage.CreateInMemory(), mChan, "localhost") + }) +} + +func TestAcceptMessage(t *testing.T) { + Convey("acceptMessage should be called", t, func() { + mbuf := "EHLO localhost\nMAIL FROM:\nRCPT TO:\nDATA\nHi.\r\n.\r\nQUIT\n" + var rbuf []byte + frw := &fakeRw{ + _read: func(p []byte) (n int, err error) { + if len(p) >= len(mbuf) { + ba := []byte(mbuf) + mbuf = "" + for i, b := range ba { + p[i] = b + } + return len(ba), nil + } + + ba := []byte(mbuf[0:len(p)]) + mbuf = mbuf[len(p):] + for i, b := range ba { + p[i] = b + } + return len(ba), nil + }, + _write: func(p []byte) (n int, err error) { + rbuf = append(rbuf, p...) + return len(p), nil + }, + _close: func() error { + return nil + }, + } + mChan := make(chan *data.Message) + var wg sync.WaitGroup + wg.Add(1) + handlerCalled := false + go func() { + handlerCalled = true + m := <-mChan + So(m, ShouldNotBeNil) + wg.Done() + }() + Accept("1.1.1.1:11111", frw, storage.CreateInMemory(), mChan, "localhost") + wg.Wait() + So(handlerCalled, ShouldBeTrue) + }) +} + func TestValidateAuthentication(t *testing.T) { Convey("validateAuthentication is always successful", t, func() { c := &Session{} diff --git a/main.go b/main.go index e1431e3..c384aeb 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,7 @@ import ( "os" "github.com/ian-kent/Go-MailHog/mailhog/config" + "github.com/ian-kent/Go-MailHog/mailhog/data" mhhttp "github.com/ian-kent/Go-MailHog/mailhog/http" "github.com/ian-kent/Go-MailHog/mailhog/http/api" smtp "github.com/ian-kent/Go-MailHog/mailhog/smtp/server" @@ -42,7 +43,7 @@ func configure() { MongoDb: mongodb, MongoColl: mongocoll, Assets: Asset, - MessageChan: make(chan interface{}), + MessageChan: make(chan *data.Message), } if storage_type == "mongodb" { @@ -123,6 +124,12 @@ func smtp_listen() *net.TCPListener { } defer conn.Close() - go smtp.Accept(conn.(*net.TCPConn).RemoteAddr().String(), io.ReadWriteCloser(conn), conf) + go smtp.Accept( + conn.(*net.TCPConn).RemoteAddr().String(), + io.ReadWriteCloser(conn), + conf.Storage, + conf.MessageChan, + conf.Hostname, + ) } }