mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-18 10:07:02 +00:00
test: impl StoreStub.MarkSeen (#443)
* test: impl StoreStub.MarkSeen Signed-off-by: James Hillyerd <james@hillyerd.com> * continue to Message interface in StoreStub Signed-off-by: James Hillyerd <james@hillyerd.com> * test errors Signed-off-by: James Hillyerd <james@hillyerd.com> --------- Signed-off-by: James Hillyerd <james@hillyerd.com>
This commit is contained in:
@@ -9,8 +9,8 @@ import (
|
|||||||
// StoreStub stubs storage.Store for testing.
|
// StoreStub stubs storage.Store for testing.
|
||||||
type StoreStub struct {
|
type StoreStub struct {
|
||||||
storage.Store
|
storage.Store
|
||||||
mailboxes map[string][]storage.Message
|
mailboxes map[string][]storage.Message // Stored messages, by mailbox.
|
||||||
deleted map[storage.Message]struct{}
|
deleted map[storage.Message]struct{} // Deleted message references.
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStore creates a new StoreStub.
|
// NewStore creates a new StoreStub.
|
||||||
@@ -25,7 +25,7 @@ func NewStore() *StoreStub {
|
|||||||
func (s *StoreStub) AddMessage(m storage.Message) (id string, err error) {
|
func (s *StoreStub) AddMessage(m storage.Message) (id string, err error) {
|
||||||
mb := m.Mailbox()
|
mb := m.Mailbox()
|
||||||
msgs := s.mailboxes[mb]
|
msgs := s.mailboxes[mb]
|
||||||
s.mailboxes[mb] = append(msgs, m)
|
s.mailboxes[mb] = append(msgs, &MessageStub{Message: m})
|
||||||
return m.ID(), nil
|
return m.ID(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,34 +50,57 @@ func (s *StoreStub) GetMessages(mailbox string) ([]storage.Message, error) {
|
|||||||
return s.mailboxes[mailbox], nil
|
return s.mailboxes[mailbox], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkSeen marks the message as having been seen.
|
||||||
|
func (s *StoreStub) MarkSeen(mailbox, id string) error {
|
||||||
|
if mailbox == "messageerr" {
|
||||||
|
return errors.New("internal error")
|
||||||
|
}
|
||||||
|
for _, m := range s.mailboxes[mailbox] {
|
||||||
|
if m.ID() == id {
|
||||||
|
if stub, ok := m.(*MessageStub); ok {
|
||||||
|
stub.seen = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("unexpected type in StoreStub.mailboxes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return storage.ErrNotExist
|
||||||
|
}
|
||||||
|
|
||||||
// RemoveMessage deletes a message by ID from the specified mailbox.
|
// RemoveMessage deletes a message by ID from the specified mailbox.
|
||||||
func (s *StoreStub) RemoveMessage(mailbox, id string) error {
|
func (s *StoreStub) RemoveMessage(mailbox, id string) error {
|
||||||
mb, ok := s.mailboxes[mailbox]
|
if mb, ok := s.mailboxes[mailbox]; ok {
|
||||||
if ok {
|
var removed storage.Message
|
||||||
var msg storage.Message
|
|
||||||
for i, m := range mb {
|
for i, m := range mb {
|
||||||
if m.ID() == id {
|
if m.ID() == id {
|
||||||
msg = m
|
removed = m
|
||||||
s.mailboxes[mailbox] = append(mb[:i], mb[i+1:]...)
|
s.mailboxes[mailbox] = append(mb[:i], mb[i+1:]...)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if msg != nil {
|
|
||||||
s.deleted[msg] = struct{}{}
|
if removed != nil {
|
||||||
|
// Clients will be checking for their original storage.Message, not our wrapper.
|
||||||
|
if stub, ok := removed.(*MessageStub); ok {
|
||||||
|
s.deleted[stub.Message] = struct{}{}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
return errors.New("unexpected type in StoreStub.mailboxes")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return storage.ErrNotExist
|
return storage.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
// VisitMailboxes accepts a function that will be called with the messages in each mailbox while it
|
// VisitMailboxes accepts a function that will be called with the messages in each mailbox while it
|
||||||
// continues to return true.
|
// continues to return true.
|
||||||
func (s *StoreStub) VisitMailboxes(f func([]storage.Message) (cont bool)) error {
|
func (s *StoreStub) VisitMailboxes(f func([]storage.Message) (cont bool)) error {
|
||||||
for _, v := range s.mailboxes {
|
for _, msgs := range s.mailboxes {
|
||||||
if !f(v) {
|
if !f(msgs) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,3 +109,14 @@ func (s *StoreStub) MessageDeleted(m storage.Message) bool {
|
|||||||
_, ok := s.deleted[m]
|
_, ok := s.deleted[m]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MessageStub wraps a storage.Message with "seen" functionality.
|
||||||
|
type MessageStub struct {
|
||||||
|
storage.Message
|
||||||
|
seen bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seen returns true if the message has been marked as seen previously.
|
||||||
|
func (m *MessageStub) Seen() bool {
|
||||||
|
return m.seen
|
||||||
|
}
|
||||||
|
|||||||
@@ -80,17 +80,25 @@ func TestStoreStubMailboxAddGetVisit(t *testing.T) {
|
|||||||
// Verify entire mailbox contents.
|
// Verify entire mailbox contents.
|
||||||
gotMsgs, err := ss.GetMessages(tc.mailbox)
|
gotMsgs, err := ss.GetMessages(tc.mailbox)
|
||||||
require.NoError(t, err, "GetMessages() should not error")
|
require.NoError(t, err, "GetMessages() should not error")
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Len(t, gotMsgs, tc.count, "GetMessages() returned wrong number of items")
|
assert.Len(t, gotMsgs, tc.count, "GetMessages() returned wrong number of items")
|
||||||
|
input:
|
||||||
for _, want := range inputMsgs {
|
for _, want := range inputMsgs {
|
||||||
assert.Contains(t, gotMsgs, want, "GetMessages() did not return expected message")
|
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.
|
// Fetch and verify individual messages.
|
||||||
for _, want := range inputMsgs {
|
for _, want := range inputMsgs {
|
||||||
got, err := ss.GetMessage(tc.mailbox, want.ID())
|
got, err := ss.GetMessage(tc.mailbox, want.ID())
|
||||||
require.NoError(t, err, "GetMessage() should not error")
|
require.NoError(t, err, "GetMessage() should not error")
|
||||||
assert.Equal(t, want, got, "GetMessage() returned unexpected value")
|
assert.Equal(t, want.Mailbox(), got.Mailbox(),
|
||||||
|
"GetMessage() returned unexpected Mailbox")
|
||||||
|
assert.Equal(t, want.ID(), got.ID(), "GetMessage() returned unexpected ID")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -122,6 +130,83 @@ func TestStoreStubMailboxAddGetVisit(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
assert.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 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)
|
||||||
|
assert.Error(t, err, "GetMessage()")
|
||||||
|
assert.NotEqual(t, storage.ErrNotExist, err)
|
||||||
|
|
||||||
|
_, err = ss.GetMessages("messageserr")
|
||||||
|
assert.Error(t, err, "GetMessages()")
|
||||||
|
assert.NotEqual(t, storage.ErrNotExist, err)
|
||||||
|
|
||||||
|
err = ss.MarkSeen("messageerr", id1)
|
||||||
|
assert.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 {
|
func makeTestMessage(mailbox string, subject string) *message.Delivery {
|
||||||
id := fmt.Sprintf("%06d", atomic.AddUint32(&testMessageIDSource, 1))
|
id := fmt.Sprintf("%06d", atomic.AddUint32(&testMessageIDSource, 1))
|
||||||
from := mail.Address{Name: "From Test", Address: "from@example.com"}
|
from := mail.Address{Name: "From Test", Address: "from@example.com"}
|
||||||
|
|||||||
Reference in New Issue
Block a user