mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-17 09:37:02 +00:00
* chore: faster hash to string conv Signed-off-by: James Hillyerd <james@hillyerd.com> * chore: require NoError in integration test setup Signed-off-by: James Hillyerd <james@hillyerd.com> --------- Signed-off-by: James Hillyerd <james@hillyerd.com>
252 lines
6.3 KiB
Go
252 lines
6.3 KiB
Go
package test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
smtpclient "net/smtp"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/inbucket/inbucket/v3/pkg/config"
|
|
"github.com/inbucket/inbucket/v3/pkg/extension"
|
|
"github.com/inbucket/inbucket/v3/pkg/message"
|
|
"github.com/inbucket/inbucket/v3/pkg/msghub"
|
|
"github.com/inbucket/inbucket/v3/pkg/policy"
|
|
"github.com/inbucket/inbucket/v3/pkg/rest"
|
|
"github.com/inbucket/inbucket/v3/pkg/rest/client"
|
|
"github.com/inbucket/inbucket/v3/pkg/server/smtp"
|
|
"github.com/inbucket/inbucket/v3/pkg/server/web"
|
|
"github.com/inbucket/inbucket/v3/pkg/storage"
|
|
"github.com/inbucket/inbucket/v3/pkg/storage/mem"
|
|
"github.com/inbucket/inbucket/v3/pkg/webui"
|
|
"github.com/jhillyerd/goldiff"
|
|
"github.com/rs/zerolog"
|
|
"github.com/rs/zerolog/log"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
const (
|
|
restBaseURL = "http://127.0.0.1:9000/"
|
|
smtpHost = "127.0.0.1:2500"
|
|
)
|
|
|
|
// TODO: Add suites for domain and full addressing modes.
|
|
type IntegrationSuite struct {
|
|
suite.Suite
|
|
stopServer func()
|
|
}
|
|
|
|
func (s *IntegrationSuite) SetupSuite() {
|
|
stopServer, err := startServer()
|
|
s.Require().NoError(err)
|
|
s.stopServer = stopServer
|
|
}
|
|
|
|
func (s *IntegrationSuite) TearDownSuite() {
|
|
s.stopServer()
|
|
}
|
|
|
|
func TestIntegrationSuite(t *testing.T) {
|
|
suite.Run(t, new(IntegrationSuite))
|
|
}
|
|
|
|
func (s *IntegrationSuite) TestBasic() {
|
|
client, err := client.New(restBaseURL)
|
|
s.Require().NoError(err)
|
|
from := "fromuser@inbucket.org"
|
|
to := []string{"recipient@inbucket.org"}
|
|
input := readTestData("basic.txt")
|
|
|
|
// Send mail.
|
|
err = smtpclient.SendMail(smtpHost, nil, from, to, input)
|
|
s.Require().NoError(err)
|
|
|
|
// Confirm receipt.
|
|
msg, err := client.GetMessage("recipient", "latest")
|
|
s.Require().NoError(err)
|
|
s.NotNil(msg)
|
|
|
|
// Compare to golden.
|
|
got := formatMessage(msg)
|
|
goldiff.File(s.T(), got, "testdata", "basic.golden")
|
|
}
|
|
|
|
func (s *IntegrationSuite) TestFullname() {
|
|
client, err := client.New(restBaseURL)
|
|
s.Require().NoError(err)
|
|
from := "fromuser@inbucket.org"
|
|
to := []string{"recipient@inbucket.org"}
|
|
input := readTestData("fullname.txt")
|
|
|
|
// Send mail.
|
|
err = smtpclient.SendMail(smtpHost, nil, from, to, input)
|
|
s.Require().NoError(err)
|
|
|
|
// Confirm receipt.
|
|
msg, err := client.GetMessage("recipient", "latest")
|
|
s.Require().NoError(err)
|
|
s.NotNil(msg)
|
|
|
|
// Compare to golden.
|
|
got := formatMessage(msg)
|
|
goldiff.File(s.T(), got, "testdata", "fullname.golden")
|
|
}
|
|
|
|
func (s *IntegrationSuite) TestEncodedHeader() {
|
|
client, err := client.New(restBaseURL)
|
|
s.Require().NoError(err)
|
|
from := "fromuser@inbucket.org"
|
|
to := []string{"recipient@inbucket.org"}
|
|
input := readTestData("encodedheader.txt")
|
|
|
|
// Send mail.
|
|
err = smtpclient.SendMail(smtpHost, nil, from, to, input)
|
|
s.Require().NoError(err)
|
|
|
|
// Confirm receipt.
|
|
msg, err := client.GetMessage("recipient", "latest")
|
|
s.Require().NoError(err)
|
|
s.NotNil(msg)
|
|
|
|
// Compare to golden.
|
|
got := formatMessage(msg)
|
|
goldiff.File(s.T(), got, "testdata", "encodedheader.golden")
|
|
}
|
|
|
|
func (s *IntegrationSuite) TestIPv4Recipient() {
|
|
client, err := client.New(restBaseURL)
|
|
s.Require().NoError(err)
|
|
from := "fromuser@inbucket.org"
|
|
to := []string{"ip4recipient@[192.168.123.123]"}
|
|
input := readTestData("no-to.txt")
|
|
|
|
// Send mail.
|
|
err = smtpclient.SendMail(smtpHost, nil, from, to, input)
|
|
s.Require().NoError(err)
|
|
|
|
// Confirm receipt.
|
|
msg, err := client.GetMessage("ip4recipient", "latest")
|
|
s.Require().NoError(err)
|
|
s.NotNil(msg)
|
|
|
|
// Compare to golden.
|
|
got := formatMessage(msg)
|
|
goldiff.File(s.T(), got, "testdata", "no-to-ipv4.golden")
|
|
}
|
|
|
|
func (s *IntegrationSuite) TestIPv6Recipient() {
|
|
client, err := client.New(restBaseURL)
|
|
s.Require().NoError(err)
|
|
from := "fromuser@inbucket.org"
|
|
to := []string{"ip6recipient@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]"}
|
|
input := readTestData("no-to.txt")
|
|
|
|
// Send mail.
|
|
err = smtpclient.SendMail(smtpHost, nil, from, to, input)
|
|
s.Require().NoError(err)
|
|
|
|
// Confirm receipt.
|
|
msg, err := client.GetMessage("ip6recipient", "latest")
|
|
s.Require().NoError(err)
|
|
s.NotNil(msg)
|
|
|
|
// Compare to golden.
|
|
got := formatMessage(msg)
|
|
goldiff.File(s.T(), got, "testdata", "no-to-ipv6.golden")
|
|
}
|
|
|
|
func formatMessage(m *client.Message) []byte {
|
|
b := &bytes.Buffer{}
|
|
fmt.Fprintf(b, "Mailbox: %v\n", m.Mailbox)
|
|
fmt.Fprintf(b, "From: %v\n", m.From)
|
|
fmt.Fprintf(b, "To: %v\n", m.To)
|
|
fmt.Fprintf(b, "Subject: %v\n", m.Subject)
|
|
fmt.Fprintf(b, "Size: %v\n", m.Size)
|
|
fmt.Fprintf(b, "\nBODY TEXT:\n%v\n", m.Body.Text)
|
|
fmt.Fprintf(b, "\nBODY HTML:\n%v\n", m.Body.HTML)
|
|
return b.Bytes()
|
|
}
|
|
|
|
func startServer() (func(), error) {
|
|
// TODO Move integration setup into lifecycle.
|
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, NoColor: true})
|
|
|
|
extHost := extension.NewHost()
|
|
|
|
// Storage setup.
|
|
storage.Constructors["memory"] = mem.New
|
|
clearEnv()
|
|
conf, err := config.Process()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
svcCtx, svcCancel := context.WithCancel(context.Background())
|
|
store, err := storage.FromConfig(conf.Storage, extHost)
|
|
if err != nil {
|
|
svcCancel()
|
|
return nil, err
|
|
}
|
|
|
|
// TODO Test should not pass with unstarted msghub.
|
|
addrPolicy := &policy.Addressing{Config: conf}
|
|
msgHub := msghub.New(conf.Web.MonitorHistory, extHost)
|
|
mmanager := &message.StoreManager{AddrPolicy: addrPolicy, Store: store, ExtHost: extHost}
|
|
|
|
// Start HTTP server.
|
|
webui.SetupRoutes(web.Router.PathPrefix("/serve/").Subrouter())
|
|
rest.SetupRoutes(web.Router.PathPrefix("/api/").Subrouter())
|
|
webServer := web.NewServer(conf, mmanager, msgHub)
|
|
go webServer.Start(svcCtx, func() {})
|
|
|
|
// Start SMTP server.
|
|
smtpServer := smtp.NewServer(conf.SMTP, mmanager, addrPolicy, extHost)
|
|
go smtpServer.Start(svcCtx, func() {})
|
|
|
|
// TODO Use a readyFunc to determine server readiness.
|
|
time.Sleep(500 * time.Millisecond)
|
|
|
|
return func() {
|
|
// Shut everything down.
|
|
svcCancel()
|
|
smtpServer.Drain()
|
|
}, nil
|
|
}
|
|
|
|
func readTestData(path ...string) []byte {
|
|
// Prefix path with testdata.
|
|
p := append([]string{"testdata"}, path...)
|
|
f, err := os.Open(filepath.Join(p...))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
data, err := io.ReadAll(f)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return data
|
|
}
|
|
|
|
// clearEnv clears environment variables, preserving any that are critical for this OS.
|
|
func clearEnv() {
|
|
preserve := make(map[string]string)
|
|
backup := func(k string) {
|
|
preserve[k] = os.Getenv(k)
|
|
}
|
|
|
|
// Backup ciritcal env variables.
|
|
if runtime.GOOS == "windows" {
|
|
backup("SYSTEMROOT")
|
|
}
|
|
|
|
os.Clearenv()
|
|
|
|
for k, v := range preserve {
|
|
os.Setenv(k, v)
|
|
}
|
|
}
|