Files
mesh-catalog/modules/mesh-mail-reader/cmd/mesh-mail-reader/kit_test.go
T

186 lines
4.0 KiB
Go

package main
// What the tests stand on: an in-memory double of Store (store.go), for the hearing (1518) and health (1519)
// tests alike. The postgres-backed PgStore (pgstore.go) is proven only by pgstore_test.go's unit tests and by
// pgstore_integration_test.go, which this context never runs.
import (
"context"
"errors"
"sync"
)
type memStore struct {
mu sync.Mutex
waiting []WaitingMail
keys map[string]bool
nextSeq int64
failNext error // AddWaiting fails once with this, then clears, so a test can prove a failure is returned
health ReaderHealth
entries []Entry
nextEntry int64
groups []Group
nextGroup int64
lessons []Lesson
nextLesson int64
}
func newMemStore() *memStore {
return &memStore{keys: map[string]bool{}, health: ReaderHealth{Healthy: true}}
}
func (s *memStore) AddWaiting(_ context.Context, w WaitingMail) error {
s.mu.Lock()
defer s.mu.Unlock()
if s.failNext != nil {
err := s.failNext
s.failNext = nil
return err
}
key := w.Key()
if s.keys[key] {
return nil // 1518/AC3: the same mail heard twice is recorded once.
}
s.keys[key] = true
s.nextSeq++
w.Seq = s.nextSeq
s.waiting = append(s.waiting, w)
return nil
}
func (s *memStore) Waiting(context.Context) ([]WaitingMail, error) {
s.mu.Lock()
defer s.mu.Unlock()
out := make([]WaitingMail, len(s.waiting))
copy(out, s.waiting) // already in arrival order: appended in the order AddWaiting succeeded (1518/AC4).
return out, nil
}
func (s *memStore) TakeWaiting(_ context.Context, seq int64) error {
s.mu.Lock()
defer s.mu.Unlock()
for i, w := range s.waiting {
if w.Seq == seq {
s.waiting = append(s.waiting[:i], s.waiting[i+1:]...)
return nil
}
}
return nil
}
func (s *memStore) ReaderHealth(context.Context) (ReaderHealth, error) {
s.mu.Lock()
defer s.mu.Unlock()
return s.health, nil
}
func (s *memStore) SetReaderHealth(_ context.Context, h ReaderHealth) error {
s.mu.Lock()
defer s.mu.Unlock()
s.health = h
return nil
}
func (s *memStore) AddEntry(_ context.Context, e Entry) (int64, error) {
s.mu.Lock()
defer s.mu.Unlock()
s.nextEntry++
e.ID = s.nextEntry
s.entries = append(s.entries, e)
return e.ID, nil
}
func (s *memStore) UpdateEntry(_ context.Context, e Entry) error {
s.mu.Lock()
defer s.mu.Unlock()
for i, existing := range s.entries {
if existing.ID == e.ID {
s.entries[i] = e
return nil
}
}
return ErrNotFound
}
func (s *memStore) Entry(_ context.Context, id int64) (Entry, bool, error) {
s.mu.Lock()
defer s.mu.Unlock()
for _, e := range s.entries {
if e.ID == id {
return e, true, nil
}
}
return Entry{}, false, nil
}
func (s *memStore) Entries(context.Context) ([]Entry, error) {
s.mu.Lock()
defer s.mu.Unlock()
out := make([]Entry, len(s.entries))
copy(out, s.entries)
return out, nil
}
func (s *memStore) FindOrCreateGroup(_ context.Context, label string) (Group, error) {
s.mu.Lock()
defer s.mu.Unlock()
for _, g := range s.groups {
if g.Label == label {
return g, nil
}
}
s.nextGroup++
g := Group{ID: s.nextGroup, Label: label}
s.groups = append(s.groups, g)
return g, nil
}
func (s *memStore) Groups(context.Context) ([]Group, error) {
s.mu.Lock()
defer s.mu.Unlock()
counts := map[int64]int{}
for _, e := range s.entries {
if e.Group != 0 {
counts[e.Group]++
}
}
out := make([]Group, len(s.groups))
for i, g := range s.groups {
g.Count = counts[g.ID]
out[i] = g
}
return out, nil
}
func (s *memStore) AddLesson(_ context.Context, l Lesson) (int64, error) {
s.mu.Lock()
defer s.mu.Unlock()
s.nextLesson++
l.ID = s.nextLesson
s.lessons = append(s.lessons, l)
return l.ID, nil
}
func (s *memStore) Lessons(context.Context) ([]Lesson, error) {
s.mu.Lock()
defer s.mu.Unlock()
out := make([]Lesson, len(s.lessons))
copy(out, s.lessons)
return out, nil
}
func (s *memStore) UndoLesson(_ context.Context, id int64) error {
s.mu.Lock()
defer s.mu.Unlock()
for i, l := range s.lessons {
if l.ID == id {
s.lessons[i].Undone = true
return nil
}
}
return ErrNotFound
}
var errStoreFake = errors.New("the store refused (fake, for a test)")