package console import ( "context" "errors" "sync" "github.com/carlosframework/platform/internal/release" ) // hookStore is the recording store the lifecycle tests drive failures // through. failPut and failDelete map a key to how many more times it fails // (a negative count fails forever); onDelete runs before each Delete, which is // how a test observes the row at the moment a marker is removed; onGet runs // before each Get. type hookStore struct { release.Store mu sync.Mutex failPut map[string]int failDelete map[string]int onDelete func(key string) // onGet runs before each Get: how a test changes the bucket between two // reads of one request (Task 8's ErrNotTrashed test). onGet func(key string) deletes []string } func (h *hookStore) Get(ctx context.Context, key string) ([]byte, string, error) { if h.onGet != nil { h.onGet(key) } return h.Store.Get(ctx, key) } func (h *hookStore) fails(m map[string]int, key string) bool { h.mu.Lock() defer h.mu.Unlock() n, ok := m[key] if !ok || n == 0 { return false } if n > 0 { m[key] = n - 1 } return true } func (h *hookStore) Put(ctx context.Context, key string, body []byte, ifMatch string) (string, error) { if h.fails(h.failPut, key) { return "", errors.New("hookStore: put refused") } return h.Store.Put(ctx, key, body, ifMatch) } func (h *hookStore) Delete(ctx context.Context, key string) error { if h.onDelete != nil { h.onDelete(key) } if h.fails(h.failDelete, key) { return errors.New("hookStore: delete refused") } h.mu.Lock() h.deletes = append(h.deletes, key) h.mu.Unlock() return h.Store.Delete(ctx, key) }