1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-17 17:47:03 +00:00
Files
go-inbucket/pkg/test/integration_test.go
James Hillyerd 5729a212ce chore: two small lint fixes (#506)
* 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>
2024-02-20 12:30:04 -08:00

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