1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-17 09:37:02 +00:00
Files
go-inbucket/pkg/test/storage_test.go
James Hillyerd 9a2b0f934a chore: Update Go deps (#571)
* chore: Update Go deps

Signed-off-by: James Hillyerd <james@hillyerd.com>

* Fix lint warnings for loopvars

Signed-off-by: James Hillyerd <james@hillyerd.com>

---------

Signed-off-by: James Hillyerd <james@hillyerd.com>
2025-05-08 20:53:25 -07:00

257 lines
7.4 KiB
Go

package test_test
import (
"fmt"
"net/mail"
"reflect"
"strings"
"sync/atomic"
"testing"
"time"
"github.com/inbucket/inbucket/v3/pkg/extension/event"
"github.com/inbucket/inbucket/v3/pkg/message"
"github.com/inbucket/inbucket/v3/pkg/storage"
"github.com/inbucket/inbucket/v3/pkg/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var testMessageIDSource uint32
func TestStoreStubMailboxAddGetVisit(t *testing.T) {
ss := test.NewStore()
tcs := []struct {
mailbox string
count int
}{
{mailbox: "box1", count: 1},
{mailbox: "box2", count: 1},
{mailbox: "box3", count: 3},
}
for _, tc := range tcs {
t.Run(tc.mailbox, func(t *testing.T) {
var err error
// Add messages.
inputMsgs := make([]*message.Delivery, tc.count)
for i := range inputMsgs {
subject := fmt.Sprintf("%s message %v", tc.mailbox, i)
inputMsgs[i] = makeTestMessage(tc.mailbox, subject)
id, err := ss.AddMessage(inputMsgs[i])
require.NoError(t, err)
require.NotEmpty(t, id, "AddMessage() must return an ID")
}
// Verify entire mailbox contents.
gotMsgs, err := ss.GetMessages(tc.mailbox)
require.NoError(t, err, "GetMessages() should not error")
assert.Len(t, gotMsgs, tc.count, "GetMessages() returned wrong number of items")
input:
for _, want := range inputMsgs {
for _, got := range gotMsgs {
if got.ID() == want.ID() && got.Mailbox() == want.Mailbox() {
continue input
}
}
t.Errorf("GetMessages() did not return message %q for mailbox %q",
want.ID(), want.Mailbox())
}
// Fetch and verify individual messages.
for _, want := range inputMsgs {
got, err := ss.GetMessage(tc.mailbox, want.ID())
require.NoError(t, err, "GetMessage() should not error")
assert.Equal(t, want.Mailbox(), got.Mailbox(),
"GetMessage() returned unexpected Mailbox")
assert.Equal(t, want.ID(), got.ID(), "GetMessage() returned unexpected ID")
}
})
}
t.Run("VisitMailboxes counts", func(t *testing.T) {
expectCounts := make(map[string]int, len(tcs))
for _, tc := range tcs {
expectCounts[tc.mailbox] = tc.count
}
// Verify message count of each visited mailbox.
err := ss.VisitMailboxes(func(m []storage.Message) (cont bool) {
require.NotEmpty(t, m, "Visitor called with empty message slice")
mailbox := m[0].Mailbox()
want, ok := expectCounts[mailbox]
assert.True(t, ok, "Mailbox %q was unexpected", mailbox)
assert.Len(t, m, want, "Unexpected message count for mailbox %q", mailbox)
delete(expectCounts, mailbox)
return true
})
require.NoError(t, err, "VisitMailboxes() must not fail")
// Verify all mailboxes were visited.
assert.Empty(t, expectCounts, "Failed to visit mailboxes: %v",
reflect.ValueOf(expectCounts).MapKeys())
})
}
func TestStoreStubMarkSeen(t *testing.T) {
ss := test.NewStore()
// Add messages.
inputMsgs := make([]*message.Delivery, 5)
for i := range inputMsgs {
subject := fmt.Sprintf("%s message %v", "box1", i)
inputMsgs[i] = makeTestMessage("box1", subject)
id, err := ss.AddMessage(inputMsgs[i])
require.NoError(t, err)
require.NotEmpty(t, id, "AddMessage() must return an ID")
}
// Mark second message as seen.
seen := inputMsgs[1]
err := ss.MarkSeen("box1", seen.ID())
require.NoError(t, err, "MarkSeen must not fail")
// Verify message has seen flag.
got, err := ss.GetMessage("box1", seen.ID())
require.NoError(t, err)
assert.True(t, got.Seen(), "Message should have been seen")
// Verify only one message seen.
gotMsgs, err := ss.GetMessages("box1")
require.NoError(t, err, "GetMessages() should not error")
assert.Len(t, gotMsgs, len(inputMsgs), "GetMessages() returned wrong number of items")
gotCount := 0
for _, msg := range gotMsgs {
if msg.Seen() {
gotCount++
}
}
assert.Equal(t, 1, gotCount, "Incorrect number of seen messages")
}
func TestStoreStubRemoveMessage(t *testing.T) {
ss := test.NewStore()
// Add messages.
inputMsgs := make([]*message.Delivery, 5)
for i := range inputMsgs {
subject := fmt.Sprintf("%s message %v", "box1", i)
inputMsgs[i] = makeTestMessage("box1", subject)
id, err := ss.AddMessage(inputMsgs[i])
require.NoError(t, err)
require.NotEmpty(t, id, "AddMessage() must return an ID")
}
// Delete second message.
deleted := inputMsgs[1]
err := ss.RemoveMessage("box1", deleted.ID())
require.NoError(t, err, "DeleteMessage must not fail")
// Verify message is not in mailbox.
messages, err := ss.GetMessages("box1")
require.NoError(t, err)
assert.NotContains(t, messages, deleted, "Mailbox should not contain msg %q", deleted.ID())
// Verify message is no longer retrievable.
got, err := ss.GetMessage("box1", deleted.ID())
require.Error(t, err)
assert.Nil(t, got, "Message should have been nil")
// Verify message is in deleted list.
assert.True(t, ss.MessageDeleted(deleted), "Message %q should be in deleted list", deleted.ID())
}
func TestStoreStubPurgeMessages(t *testing.T) {
ss := test.NewStore()
// Add messages.
inputMsgs := make([]*message.Delivery, 5)
for i := range inputMsgs {
subject := fmt.Sprintf("%s message %v", "box1", i)
inputMsgs[i] = makeTestMessage("box1", subject)
id, err := ss.AddMessage(inputMsgs[i])
require.NoError(t, err)
require.NotEmpty(t, id, "AddMessage() must return an ID")
}
// Purge messages.
err := ss.PurgeMessages("box1")
require.NoError(t, err, "PurgeMessages must not fail")
// Verify message is not in mailbox.
messages, err := ss.GetMessages("box1")
require.NoError(t, err)
assert.Empty(t, messages, "Mailbox should be empty")
// Verify messages are in deleted list.
for _, want := range inputMsgs {
assert.True(t, ss.MessageDeleted(want), "Message %q should be in deleted list", want.ID())
}
}
func TestStoreStubForcedErrors(t *testing.T) {
ss := test.NewStore()
var err error
// Add message to forced error mailboxes.
msg := makeTestMessage("messageerr", "test 1")
id1, err := ss.AddMessage(msg)
require.NoError(t, err)
msg = makeTestMessage("messageserr", "test 2")
_, err = ss.AddMessage(msg)
require.NoError(t, err)
// Verify methods return error.
_, err = ss.GetMessage("messageerr", id1)
require.Error(t, err, "GetMessage()")
assert.NotEqual(t, storage.ErrNotExist, err)
_, err = ss.GetMessages("messageserr")
require.Error(t, err, "GetMessages()")
assert.NotEqual(t, storage.ErrNotExist, err)
err = ss.MarkSeen("messageerr", id1)
require.Error(t, err, "MarkSeen()")
assert.NotEqual(t, storage.ErrNotExist, err)
}
func TestStoreStubNotExistErrors(t *testing.T) {
ss := test.NewStore()
var err error
// Verify methods return error.
_, err = ss.GetMessage("fake", "1")
assert.Equal(t, storage.ErrNotExist, err, "GetMessage()")
err = ss.MarkSeen("fake", "1")
assert.Equal(t, storage.ErrNotExist, err, "MarkSeen()")
err = ss.RemoveMessage("fake", "1")
assert.Equal(t, storage.ErrNotExist, err, "RemoveMessage()")
}
func makeTestMessage(mailbox string, subject string) *message.Delivery {
id := fmt.Sprintf("%06d", atomic.AddUint32(&testMessageIDSource, 1))
from := mail.Address{Name: "From Test", Address: "from@example.com"}
to := mail.Address{Name: "To Test", Address: "to@example.com"}
return &message.Delivery{
Meta: event.MessageMetadata{
ID: id,
Mailbox: mailbox,
From: &from,
To: []*mail.Address{&to},
Date: time.Now(),
Subject: subject,
},
Reader: strings.NewReader(fmt.Sprintf(
"From: %s\nTo: %s\nSubject: %s\n\nTest message about %q\n",
from, to, subject, subject,
)),
}
}