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)")