186 lines
4.0 KiB
Go
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)")
|