1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-19 10:37:01 +00:00

Refactoring to support REST unit tests

This commit is contained in:
James Hillyerd
2013-11-11 10:50:41 -08:00
parent 2e1c937d23
commit 414ed44882
5 changed files with 214 additions and 16 deletions

View File

@@ -1 +1 @@
curl -i -H "Accept: application/json" --noproxy localhost http://localhost:9000/mailbox/$1 curl -i -H "Accept: application/json" --noproxy localhost "http://localhost:9000/mailbox/$1"

View File

@@ -98,6 +98,7 @@ func main() {
ds := smtpd.DefaultFileDataStore() ds := smtpd.DefaultFileDataStore()
// Start HTTP server // Start HTTP server
web.Initialize(config.GetWebConfig(), ds)
go web.Start() go web.Start()
// Start POP3 server // Start POP3 server

195
web/rest_test.go Normal file
View File

@@ -0,0 +1,195 @@
package web
import (
"bytes"
"github.com/jhillyerd/go.enmime"
"github.com/jhillyerd/inbucket/config"
"github.com/jhillyerd/inbucket/smtpd"
"github.com/stretchr/testify/mock"
"io"
"log"
"net/http"
"net/http/httptest"
"net/mail"
"os"
"testing"
"time"
)
func TestRestMailboxList(t *testing.T) {
// Create Mock Objects
ds := &MockDataStore{}
emptybox := &MockMailbox{}
ds.On("MailboxFor", "empty").Return(emptybox, nil)
emptybox.On("GetMessages").Return([]smtpd.Message{}, nil)
logbuf := setupWebServer(ds)
// Test invalid mailbox name
w, err := testRestGet("http://localhost/mailbox/foo@bar")
expectCode := 500
if err != nil {
t.Fatal(err)
}
if w.Code != expectCode {
t.Errorf("Expected code %v, got %v", expectCode, w.Code)
}
// Test empty mailbox
w, err = testRestGet("http://localhost/mailbox/empty")
expectCode = 200
if err != nil {
t.Fatal(err)
}
if w.Code != expectCode {
t.Errorf("Expected code %v, got %v", expectCode, w.Code)
}
if t.Failed() {
// Wait for handler to finish logging
time.Sleep(2 * time.Second)
// Dump buffered log data if there was a failure
io.Copy(os.Stderr, logbuf)
}
}
func testRestGet(url string) (*httptest.ResponseRecorder, error) {
req, err := http.NewRequest("GET", url, nil)
req.Header.Add("Accept", "application/json")
if err != nil {
return nil, err
}
w := httptest.NewRecorder()
Router.ServeHTTP(w, req)
return w, nil
}
func setupWebServer(ds smtpd.DataStore) *bytes.Buffer {
// Capture log output
buf := new(bytes.Buffer)
log.SetOutput(buf)
cfg := config.WebConfig{
TemplateDir: "../themes/integral/templates",
PublicDir: "../themes/integral/public",
}
Initialize(cfg, ds)
return buf
}
// Mock DataStore object
type MockDataStore struct {
mock.Mock
}
func (m *MockDataStore) MailboxFor(name string) (smtpd.Mailbox, error) {
args := m.Called(name)
return args.Get(0).(smtpd.Mailbox), args.Error(1)
}
func (m *MockDataStore) AllMailboxes() ([]smtpd.Mailbox, error) {
args := m.Called()
return args.Get(0).([]smtpd.Mailbox), args.Error(1)
}
// Mock Mailbox object
type MockMailbox struct {
mock.Mock
}
func (m *MockMailbox) GetMessages() ([]smtpd.Message, error) {
args := m.Called()
return args.Get(0).([]smtpd.Message), args.Error(1)
}
func (m *MockMailbox) GetMessage(id string) (smtpd.Message, error) {
args := m.Called(id)
return args.Get(0).(smtpd.Message), args.Error(1)
}
func (m *MockMailbox) Purge() error {
args := m.Called()
return args.Error(0)
}
func (m *MockMailbox) NewMessage() smtpd.Message {
args := m.Called()
return args.Get(0).(smtpd.Message)
}
func (m *MockMailbox) String() string {
args := m.Called()
return args.String(0)
}
// Mock Message object
type MockMessage struct {
mock.Mock
}
func (m *MockMessage) Id() string {
args := m.Called()
return args.String(0)
}
func (m *MockMessage) From() string {
args := m.Called()
return args.String(0)
}
func (m *MockMessage) Date() time.Time {
args := m.Called()
return args.Get(0).(time.Time)
}
func (m *MockMessage) Subject() string {
args := m.Called()
return args.String(0)
}
func (m *MockMessage) ReadHeader() (msg *mail.Message, err error) {
args := m.Called()
return args.Get(0).(*mail.Message), args.Error(1)
}
func (m *MockMessage) ReadBody() (body *enmime.MIMEBody, err error) {
args := m.Called()
return args.Get(0).(*enmime.MIMEBody), args.Error(1)
}
func (m *MockMessage) ReadRaw() (raw *string, err error) {
args := m.Called()
return args.Get(0).(*string), args.Error(1)
}
func (m *MockMessage) RawReader() (reader io.ReadCloser, err error) {
args := m.Called()
return args.Get(0).(io.ReadCloser), args.Error(1)
}
func (m *MockMessage) Size() int64 {
args := m.Called()
return int64(args.Int(0))
}
func (m *MockMessage) Append(data []byte) error {
// []byte arg seems to mess up testify/mock
return nil
}
func (m *MockMessage) Close() error {
args := m.Called()
return args.Error(0)
}
func (m *MockMessage) Delete() error {
args := m.Called()
return args.Error(0)
}
func (m *MockMessage) String() string {
args := m.Called()
return args.String(0)
}

View File

@@ -18,12 +18,25 @@ import (
type handler func(http.ResponseWriter, *http.Request, *Context) error type handler func(http.ResponseWriter, *http.Request, *Context) error
var webConfig config.WebConfig
var DataStore smtpd.DataStore var DataStore smtpd.DataStore
var Router *mux.Router var Router *mux.Router
var listener net.Listener var listener net.Listener
var sessionStore sessions.Store var sessionStore sessions.Store
var shutdown bool var shutdown bool
// Initialize sets up things for unit tests or the Start() method
func Initialize(cfg config.WebConfig, ds smtpd.DataStore) {
webConfig = cfg
setupRoutes(cfg)
// NewContext() will use this DataStore for the web handlers
DataStore = ds
// TODO Make configurable
sessionStore = sessions.NewCookieStore([]byte("something-very-secret"))
}
func setupRoutes(cfg config.WebConfig) { func setupRoutes(cfg config.WebConfig) {
log.LogInfo("Theme templates mapped to '%v'", cfg.TemplateDir) log.LogInfo("Theme templates mapped to '%v'", cfg.TemplateDir)
log.LogInfo("Theme static content mapped to '%v'", cfg.PublicDir) log.LogInfo("Theme static content mapped to '%v'", cfg.PublicDir)
@@ -54,16 +67,7 @@ func setupRoutes(cfg config.WebConfig) {
// Start() the web server // Start() the web server
func Start() { func Start() {
cfg := config.GetWebConfig() addr := fmt.Sprintf("%v:%v", webConfig.Ip4address, webConfig.Ip4port)
setupRoutes(cfg)
// NewContext() will use this DataStore for the web handlers
DataStore = smtpd.DefaultFileDataStore()
// TODO Make configurable
sessionStore = sessions.NewCookieStore([]byte("something-very-secret"))
addr := fmt.Sprintf("%v:%v", cfg.Ip4address, cfg.Ip4port)
server := &http.Server{ server := &http.Server{
Addr: addr, Addr: addr,
Handler: nil, Handler: nil,

View File

@@ -1,7 +1,6 @@
package web package web
import ( import (
"github.com/jhillyerd/inbucket/config"
"github.com/jhillyerd/inbucket/log" "github.com/jhillyerd/inbucket/log"
"html/template" "html/template"
"net/http" "net/http"
@@ -49,9 +48,8 @@ func ParseTemplate(name string, partial bool) (*template.Template, error) {
return t, nil return t, nil
} }
cfg := config.GetWebConfig()
tempPath := strings.Replace(name, "/", string(filepath.Separator), -1) tempPath := strings.Replace(name, "/", string(filepath.Separator), -1)
tempFile := filepath.Join(cfg.TemplateDir, tempPath) tempFile := filepath.Join(webConfig.TemplateDir, tempPath)
log.LogTrace("Parsing template %v", tempFile) log.LogTrace("Parsing template %v", tempFile)
var err error var err error
@@ -63,14 +61,14 @@ func ParseTemplate(name string, partial bool) (*template.Template, error) {
t, err = t.ParseFiles(tempFile) t, err = t.ParseFiles(tempFile)
} else { } else {
t = template.New("_base.html").Funcs(TemplateFuncs) t = template.New("_base.html").Funcs(TemplateFuncs)
t, err = t.ParseFiles(filepath.Join(cfg.TemplateDir, "_base.html"), tempFile) t, err = t.ParseFiles(filepath.Join(webConfig.TemplateDir, "_base.html"), tempFile)
} }
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Allows us to disable caching for theme development // Allows us to disable caching for theme development
if cfg.TemplateCache { if webConfig.TemplateCache {
if partial { if partial {
log.LogTrace("Caching partial %v", name) log.LogTrace("Caching partial %v", name)
cachedTemplates[name] = t cachedTemplates[name] = t