2022-07-29 13:23:08 +02:00
|
|
|
package storage
|
|
|
|
|
|
|
|
import (
|
2022-07-30 13:48:57 +02:00
|
|
|
"bytes"
|
2022-07-29 13:23:08 +02:00
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
2022-07-30 13:48:57 +02:00
|
|
|
"math/rand"
|
2022-08-05 11:35:57 +02:00
|
|
|
"os"
|
|
|
|
"path"
|
2022-07-29 13:23:08 +02:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/axllent/mailpit/config"
|
2022-07-30 13:48:57 +02:00
|
|
|
"github.com/jhillyerd/enmime"
|
2022-08-07 13:07:36 +02:00
|
|
|
"github.com/ostafen/clover/v2"
|
2022-07-29 13:23:08 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
testTextEmail []byte
|
|
|
|
testMimeEmail []byte
|
2022-08-10 04:33:16 +02:00
|
|
|
testRuns = 1000
|
2022-07-29 13:23:08 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestTextEmailInserts(t *testing.T) {
|
2022-08-05 11:35:57 +02:00
|
|
|
setup(false)
|
|
|
|
t.Log("Testing memory storage")
|
2022-07-29 13:23:08 +02:00
|
|
|
|
2022-08-05 11:35:57 +02:00
|
|
|
RepeatTest:
|
2022-07-29 13:23:08 +02:00
|
|
|
start := time.Now()
|
2022-08-07 13:07:36 +02:00
|
|
|
|
|
|
|
assertEqualStats(t, 0, 0)
|
|
|
|
|
2022-08-10 04:33:16 +02:00
|
|
|
for i := 0; i < testRuns; i++ {
|
2022-07-29 13:23:08 +02:00
|
|
|
if _, err := Store(DefaultMailbox, testTextEmail); err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
count, err := Count(DefaultMailbox)
|
|
|
|
if err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
|
2022-08-10 04:33:16 +02:00
|
|
|
assertEqual(t, count, testRuns, "incorrect number of text emails stored")
|
2022-07-29 13:23:08 +02:00
|
|
|
|
2022-08-10 04:33:16 +02:00
|
|
|
t.Logf("inserted %d text emails in %s", testRuns, time.Since(start))
|
2022-07-29 13:23:08 +02:00
|
|
|
|
2022-08-10 04:33:16 +02:00
|
|
|
assertEqualStats(t, testRuns, testRuns)
|
2022-08-07 13:07:36 +02:00
|
|
|
|
2022-07-29 13:23:08 +02:00
|
|
|
delStart := time.Now()
|
|
|
|
if err := DeleteAllMessages(DefaultMailbox); err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
|
|
|
|
count, err = Count(DefaultMailbox)
|
|
|
|
if err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
|
|
|
|
assertEqual(t, count, 0, "incorrect number of text emails deleted")
|
|
|
|
|
2022-08-10 04:33:16 +02:00
|
|
|
t.Logf("deleted %d text emails in %s", testRuns, time.Since(delStart))
|
2022-07-29 13:23:08 +02:00
|
|
|
|
2022-08-07 13:07:36 +02:00
|
|
|
assertEqualStats(t, 0, 0)
|
|
|
|
|
2022-07-29 13:23:08 +02:00
|
|
|
db.Close()
|
2022-08-05 11:35:57 +02:00
|
|
|
if config.DataDir == "" {
|
|
|
|
setup(true)
|
|
|
|
t.Logf("Testing physical storage to %s", config.DataDir)
|
|
|
|
defer os.RemoveAll(config.DataDir)
|
|
|
|
goto RepeatTest
|
|
|
|
}
|
|
|
|
|
2022-07-29 13:23:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestMimeEmailInserts(t *testing.T) {
|
2022-08-05 11:35:57 +02:00
|
|
|
setup(false)
|
|
|
|
t.Log("Testing memory storage")
|
2022-07-29 13:23:08 +02:00
|
|
|
|
2022-08-05 11:35:57 +02:00
|
|
|
RepeatTest:
|
2022-07-29 13:23:08 +02:00
|
|
|
start := time.Now()
|
2022-08-07 13:07:36 +02:00
|
|
|
|
|
|
|
assertEqualStats(t, 0, 0)
|
|
|
|
|
2022-08-10 04:33:16 +02:00
|
|
|
for i := 0; i < testRuns; i++ {
|
2022-07-29 13:23:08 +02:00
|
|
|
if _, err := Store(DefaultMailbox, testMimeEmail); err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
count, err := Count(DefaultMailbox)
|
|
|
|
if err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
|
2022-08-10 04:33:16 +02:00
|
|
|
assertEqual(t, count, testRuns, "incorrect number of emails with mime attachments stored")
|
2022-07-29 13:23:08 +02:00
|
|
|
|
2022-08-10 04:33:16 +02:00
|
|
|
t.Logf("inserted %d emails with mime attachments in %s", testRuns, time.Since(start))
|
2022-07-29 13:23:08 +02:00
|
|
|
|
2022-08-10 04:33:16 +02:00
|
|
|
assertEqualStats(t, testRuns, testRuns)
|
2022-08-07 13:07:36 +02:00
|
|
|
|
2022-07-29 13:23:08 +02:00
|
|
|
delStart := time.Now()
|
|
|
|
if err := DeleteAllMessages(DefaultMailbox); err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
|
|
|
|
count, err = Count(DefaultMailbox)
|
|
|
|
if err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
|
2022-08-10 04:33:16 +02:00
|
|
|
assertEqual(t, count, 0, "incorrect number of emails with mime attachments deleted")
|
2022-07-29 13:23:08 +02:00
|
|
|
|
2022-08-10 04:33:16 +02:00
|
|
|
t.Logf("deleted %d emails with mime attachments in %s", testRuns, time.Since(delStart))
|
2022-07-29 13:23:08 +02:00
|
|
|
|
2022-08-07 13:07:36 +02:00
|
|
|
assertEqualStats(t, 0, 0)
|
|
|
|
|
2022-07-29 13:23:08 +02:00
|
|
|
db.Close()
|
2022-08-05 11:35:57 +02:00
|
|
|
if config.DataDir == "" {
|
|
|
|
setup(true)
|
|
|
|
t.Logf("Testing physical storage to %s", config.DataDir)
|
|
|
|
defer os.RemoveAll(config.DataDir)
|
|
|
|
goto RepeatTest
|
|
|
|
}
|
2022-07-29 13:23:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestRetrieveMimeEmail(t *testing.T) {
|
2022-08-05 11:35:57 +02:00
|
|
|
setup(false)
|
|
|
|
t.Log("Testing memory storage")
|
2022-07-29 13:23:08 +02:00
|
|
|
|
2022-08-05 11:35:57 +02:00
|
|
|
RepeatTest:
|
2022-07-29 13:23:08 +02:00
|
|
|
id, err := Store(DefaultMailbox, testMimeEmail)
|
|
|
|
if err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
|
|
|
|
msg, err := GetMessage(DefaultMailbox, id)
|
|
|
|
if err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
|
|
|
|
assertEqual(t, msg.From.Name, "Sender Smith", "\"From\" name does not match")
|
|
|
|
assertEqual(t, msg.From.Address, "sender@example.com", "\"From\" address does not match")
|
|
|
|
assertEqual(t, msg.Subject, "inline + attachment", "subject does not match")
|
|
|
|
assertEqual(t, len(msg.To), 1, "incorrect number of recipients")
|
|
|
|
assertEqual(t, msg.To[0].Name, "Recipient Ross", "\"To\" name does not match")
|
|
|
|
assertEqual(t, msg.To[0].Address, "recipient@example.com", "\"To\" address does not match")
|
|
|
|
assertEqual(t, len(msg.Attachments), 1, "incorrect number of attachments")
|
|
|
|
assertEqual(t, msg.Attachments[0].FileName, "Sample PDF.pdf", "attachment filename does not match")
|
|
|
|
assertEqual(t, len(msg.Inline), 1, "incorrect number of inline attachments")
|
|
|
|
assertEqual(t, msg.Inline[0].FileName, "inline-image.jpg", "inline attachment filename does not match")
|
|
|
|
attachmentData, err := GetAttachmentPart(DefaultMailbox, id, msg.Attachments[0].PartID)
|
|
|
|
assertEqual(t, len(attachmentData.Content), msg.Attachments[0].Size, "attachment size does not match")
|
|
|
|
inlineData, err := GetAttachmentPart(DefaultMailbox, id, msg.Inline[0].PartID)
|
|
|
|
assertEqual(t, len(inlineData.Content), msg.Inline[0].Size, "inline attachment size does not match")
|
2022-07-30 13:48:57 +02:00
|
|
|
|
|
|
|
db.Close()
|
2022-08-05 11:35:57 +02:00
|
|
|
|
|
|
|
if config.DataDir == "" {
|
|
|
|
setup(true)
|
|
|
|
t.Logf("Testing physical storage to %s", config.DataDir)
|
|
|
|
defer os.RemoveAll(config.DataDir)
|
|
|
|
goto RepeatTest
|
|
|
|
}
|
2022-07-30 13:48:57 +02:00
|
|
|
}
|
|
|
|
|
2022-08-07 13:07:36 +02:00
|
|
|
func TestDatabaseStats(t *testing.T) {
|
|
|
|
setup(false)
|
|
|
|
t.Log("Testing database stats")
|
|
|
|
assertEqualStats(t, 0, 0)
|
|
|
|
|
|
|
|
for i := 0; i < 100; i++ {
|
|
|
|
if _, err := Store(DefaultMailbox, testTextEmail); err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assertEqualStats(t, 100, 100)
|
|
|
|
|
|
|
|
// mark 10 as read
|
|
|
|
docs, err := db.FindAll(
|
|
|
|
clover.NewQuery(DefaultMailbox).
|
|
|
|
Limit(10),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, d := range docs {
|
|
|
|
_, err := GetMessage(DefaultMailbox, d.ObjectId())
|
|
|
|
if err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assertEqualStats(t, 100, 90)
|
|
|
|
|
|
|
|
if err := MarkAllRead(DefaultMailbox); err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
|
|
|
|
assertEqualStats(t, 100, 0)
|
|
|
|
|
|
|
|
db.Close()
|
|
|
|
}
|
|
|
|
|
2022-07-30 13:48:57 +02:00
|
|
|
func TestSearch(t *testing.T) {
|
2022-08-05 11:35:57 +02:00
|
|
|
setup(false)
|
|
|
|
t.Log("Testing memory storage")
|
2022-07-30 13:48:57 +02:00
|
|
|
|
2022-08-05 11:35:57 +02:00
|
|
|
RepeatTest:
|
2022-08-10 04:33:16 +02:00
|
|
|
for i := 0; i < testRuns; i++ {
|
2022-07-30 13:48:57 +02:00
|
|
|
msg := enmime.Builder().
|
|
|
|
From(fmt.Sprintf("From %d", i), fmt.Sprintf("from-%d@example.com", i)).
|
|
|
|
Subject(fmt.Sprintf("Subject line %d end", i)).
|
|
|
|
Text([]byte(fmt.Sprintf("This is the email body %d <jdsauk;dwqmdqw;>.", i))).
|
|
|
|
To(fmt.Sprintf("To %d", i), fmt.Sprintf("to-%d@example.com", i))
|
|
|
|
|
|
|
|
env, err := msg.Build()
|
|
|
|
if err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
|
|
|
|
if err := env.Encode(buf); err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := Store(DefaultMailbox, buf.Bytes()); err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-10 04:33:16 +02:00
|
|
|
for i := 1; i < 51; i++ {
|
2022-07-30 13:48:57 +02:00
|
|
|
// search a random something that will return a single result
|
|
|
|
searchIndx := rand.Intn(4) + 1
|
|
|
|
var search string
|
|
|
|
switch searchIndx {
|
|
|
|
case 1:
|
|
|
|
search = fmt.Sprintf("from-%d@example.com", i)
|
|
|
|
case 2:
|
|
|
|
search = fmt.Sprintf("to-%d@example.com", i)
|
|
|
|
case 3:
|
|
|
|
search = fmt.Sprintf("Subject line %d end", i)
|
|
|
|
default:
|
|
|
|
search = fmt.Sprintf("the email body %d jdsauk dwqmdqw", i)
|
|
|
|
}
|
|
|
|
|
2022-08-10 04:33:16 +02:00
|
|
|
summaries, err := Search(DefaultMailbox, search, 0, 10)
|
2022-07-30 13:48:57 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
|
|
|
|
assertEqual(t, len(summaries), 1, "1 search result expected")
|
|
|
|
|
|
|
|
assertEqual(t, summaries[0].From.Name, fmt.Sprintf("From %d", i), "\"From\" name does not match")
|
|
|
|
assertEqual(t, summaries[0].From.Address, fmt.Sprintf("from-%d@example.com", i), "\"From\" address does not match")
|
|
|
|
assertEqual(t, summaries[0].To[0].Name, fmt.Sprintf("To %d", i), "\"To\" name does not match")
|
|
|
|
assertEqual(t, summaries[0].To[0].Address, fmt.Sprintf("to-%d@example.com", i), "\"To\" address does not match")
|
|
|
|
assertEqual(t, summaries[0].Subject, fmt.Sprintf("Subject line %d end", i), "\"Subject\" does not match")
|
|
|
|
}
|
|
|
|
|
|
|
|
// search something that will return 200 rsults
|
2022-08-10 04:33:16 +02:00
|
|
|
summaries, err := Search(DefaultMailbox, "This is the email body", 0, 50)
|
2022-07-30 13:48:57 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Log("error ", err)
|
|
|
|
t.Fail()
|
|
|
|
}
|
2022-08-10 04:33:16 +02:00
|
|
|
assertEqual(t, len(summaries), 50, "50 search results expected")
|
2022-07-30 13:48:57 +02:00
|
|
|
|
|
|
|
db.Close()
|
2022-08-05 11:35:57 +02:00
|
|
|
|
|
|
|
if config.DataDir == "" {
|
|
|
|
setup(true)
|
|
|
|
t.Logf("Testing physical storage to %s", config.DataDir)
|
|
|
|
defer os.RemoveAll(config.DataDir)
|
|
|
|
goto RepeatTest
|
|
|
|
}
|
2022-07-29 13:23:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkImportText(b *testing.B) {
|
2022-08-05 11:35:57 +02:00
|
|
|
setup(false)
|
2022-07-29 13:23:08 +02:00
|
|
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
if _, err := Store(DefaultMailbox, testTextEmail); err != nil {
|
|
|
|
b.Log("error ", err)
|
|
|
|
b.Fail()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
db.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkImportMime(b *testing.B) {
|
2022-08-05 11:35:57 +02:00
|
|
|
setup(false)
|
2022-07-29 13:23:08 +02:00
|
|
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
if _, err := Store(DefaultMailbox, testMimeEmail); err != nil {
|
|
|
|
b.Log("error ", err)
|
|
|
|
b.Fail()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
db.Close()
|
|
|
|
}
|
|
|
|
|
2022-08-05 11:35:57 +02:00
|
|
|
func setup(dataDir bool) {
|
2022-07-29 13:23:08 +02:00
|
|
|
config.NoLogging = true
|
|
|
|
config.MaxMessages = 0
|
2022-08-05 11:35:57 +02:00
|
|
|
|
|
|
|
if dataDir {
|
|
|
|
config.DataDir = fmt.Sprintf("%s-%d", path.Join(os.TempDir(), "mailpit-tests"), time.Now().UnixNano())
|
|
|
|
} else {
|
|
|
|
config.DataDir = ""
|
|
|
|
}
|
|
|
|
|
2022-07-29 13:23:08 +02:00
|
|
|
if err := InitDB(); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
testTextEmail, err = ioutil.ReadFile("testdata/plain-text.eml")
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
testMimeEmail, err = ioutil.ReadFile("testdata/mime-attachment.eml")
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertEqual(t *testing.T, a interface{}, b interface{}, message string) {
|
|
|
|
if a == b {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
message = fmt.Sprintf("%s: \"%v\" != \"%v\"", message, a, b)
|
|
|
|
t.Fatal(message)
|
|
|
|
}
|
2022-08-07 13:07:36 +02:00
|
|
|
|
|
|
|
func assertEqualStats(t *testing.T, total int, unread int) {
|
|
|
|
s := StatsGet(DefaultMailbox)
|
|
|
|
if total != s.Total {
|
|
|
|
t.Fatal(fmt.Sprintf("Incorrect total mailbox stats: \"%d\" != \"%d\"", total, s.Total))
|
|
|
|
}
|
|
|
|
|
|
|
|
if unread != s.Unread {
|
|
|
|
t.Fatal(fmt.Sprintf("Incorrect unread mailbox stats: \"%d\" != \"%d\"", unread, s.Unread))
|
|
|
|
}
|
|
|
|
}
|