mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-19 02:27:03 +00:00
Refactoring to support REST unit tests
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
@@ -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
195
web/rest_test.go
Normal 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)
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user