Add session tests

This commit is contained in:
Ian Kent 2014-11-23 12:43:33 +00:00
parent fe4748f583
commit cb5e79debb
4 changed files with 125 additions and 16 deletions

View file

@ -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)
}

View file

@ -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()
}
}
}

View file

@ -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:<test>\nRCPT TO:<test>\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{}

11
main.go
View file

@ -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,
)
}
}