mirror of
https://gitlab.com/ric_harvey/MailHog.git
synced 2025-02-17 08:15:55 +00:00
Add session tests
This commit is contained in:
parent
fe4748f583
commit
cb5e79debb
4 changed files with 125 additions and 16 deletions
|
@ -1,6 +1,7 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/ian-kent/Go-MailHog/mailhog/data"
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/storage"
|
"github.com/ian-kent/Go-MailHog/mailhog/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ type Config struct {
|
||||||
MongoUri string
|
MongoUri string
|
||||||
MongoDb string
|
MongoDb string
|
||||||
MongoColl string
|
MongoColl string
|
||||||
MessageChan chan interface{}
|
MessageChan chan *data.Message
|
||||||
Storage storage.Storage
|
Storage storage.Storage
|
||||||
Assets func(asset string) ([]byte, error)
|
Assets func(asset string) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,26 +7,27 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/config"
|
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/data"
|
"github.com/ian-kent/Go-MailHog/mailhog/data"
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/smtp/protocol"
|
"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
|
// Session represents a SMTP session using net.TCPConn
|
||||||
type Session struct {
|
type Session struct {
|
||||||
conn io.ReadWriteCloser
|
conn io.ReadWriteCloser
|
||||||
proto *protocol.Protocol
|
proto *protocol.Protocol
|
||||||
conf *config.Config
|
storage storage.Storage
|
||||||
|
messageChan chan *data.Message
|
||||||
remoteAddress string
|
remoteAddress string
|
||||||
isTLS bool
|
isTLS bool
|
||||||
line string
|
line string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accept starts a new SMTP session using io.ReadWriteCloser
|
// 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 := protocol.NewProtocol()
|
||||||
proto.Hostname = conf.Hostname
|
proto.Hostname = hostname
|
||||||
session := &Session{conn, proto, conf, remoteAddress, false, ""}
|
session := &Session{conn, proto, storage, messageChan, remoteAddress, false, ""}
|
||||||
proto.LogHandler = session.logf
|
proto.LogHandler = session.logf
|
||||||
proto.MessageReceivedHandler = session.acceptMessage
|
proto.MessageReceivedHandler = session.acceptMessage
|
||||||
proto.ValidateSenderHandler = session.validateSender
|
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) {
|
func (c *Session) acceptMessage(msg *data.Message) (id string, err error) {
|
||||||
c.logf("Storing message %s", msg.ID)
|
c.logf("Storing message %s", msg.ID)
|
||||||
id, err = c.conf.Storage.Store(msg)
|
id, err = c.storage.Store(msg)
|
||||||
c.conf.MessageChan <- msg
|
c.messageChan <- msg
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,8 +73,10 @@ func (c *Session) Read() bool {
|
||||||
|
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
c.logf("Connection closed by remote host\n")
|
c.logf("Connection closed by remote host\n")
|
||||||
|
io.Closer(c.conn).Close() // not sure this is necessary?
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logf("Error reading from socket: %s\n", err)
|
c.logf("Error reading from socket: %s\n", err)
|
||||||
return false
|
return false
|
||||||
|
@ -86,6 +89,7 @@ func (c *Session) Read() bool {
|
||||||
|
|
||||||
c.line += text
|
c.line += text
|
||||||
|
|
||||||
|
for strings.Contains(c.line, "\n") {
|
||||||
line, reply := c.proto.Parse(c.line)
|
line, reply := c.proto.Parse(c.line)
|
||||||
c.line = line
|
c.line = line
|
||||||
|
|
||||||
|
@ -95,6 +99,7 @@ func (c *Session) Read() bool {
|
||||||
io.Closer(c.conn).Close()
|
io.Closer(c.conn).Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,107 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "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) {
|
func TestValidateAuthentication(t *testing.T) {
|
||||||
Convey("validateAuthentication is always successful", t, func() {
|
Convey("validateAuthentication is always successful", t, func() {
|
||||||
c := &Session{}
|
c := &Session{}
|
||||||
|
|
11
main.go
11
main.go
|
@ -7,6 +7,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/config"
|
"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"
|
mhhttp "github.com/ian-kent/Go-MailHog/mailhog/http"
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/http/api"
|
"github.com/ian-kent/Go-MailHog/mailhog/http/api"
|
||||||
smtp "github.com/ian-kent/Go-MailHog/mailhog/smtp/server"
|
smtp "github.com/ian-kent/Go-MailHog/mailhog/smtp/server"
|
||||||
|
@ -42,7 +43,7 @@ func configure() {
|
||||||
MongoDb: mongodb,
|
MongoDb: mongodb,
|
||||||
MongoColl: mongocoll,
|
MongoColl: mongocoll,
|
||||||
Assets: Asset,
|
Assets: Asset,
|
||||||
MessageChan: make(chan interface{}),
|
MessageChan: make(chan *data.Message),
|
||||||
}
|
}
|
||||||
|
|
||||||
if storage_type == "mongodb" {
|
if storage_type == "mongodb" {
|
||||||
|
@ -123,6 +124,12 @@ func smtp_listen() *net.TCPListener {
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
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,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue