issue 1840/S1: let a process delete a key, as a tools bundle can

This commit is contained in:
2026-10-22 14:36:24 +02:00
parent 2b8ada5eb9
commit 5ea6c215a4
3 changed files with 67 additions and 0 deletions
+14
View File
@@ -263,3 +263,17 @@ func (s State) Watch(key string, handle func(stdio.StateChange) error) error {
}()
return nil
}
// Delete removes a key. A key that was not there is not an error.
func (s State) Delete(key string) error {
ctx, cancel := context.WithTimeout(context.Background(), stateTimeout)
defer cancel()
kv, err := s.store(ctx)
if err != nil {
return err
}
if err := kv.Delete(ctx, key); err != nil && !errors.Is(err, jetstream.ErrKeyNotFound) {
return fmt.Errorf("%s's state %s, key %s: %w", s.Module, s.Name, key, err)
}
return nil
}
+28
View File
@@ -234,3 +234,31 @@ func TestStateWatchRefusesAnUngrantedBucketNamingIt(t *testing.T) {
t.Fatalf("Watch on an ungranted bucket: %v, want a refusal naming mesh-mail_unrelated", err)
}
}
// 1840/S1: given a process connection granted its bucket, when it deletes a key, then the key is gone and
// deleting it again is no error.
func TestStateDeleteOnAGrantedBucket(t *testing.T) {
url, account := grantedSendProcess(t)
_, adminJetStream := adminJS(t, url)
if _, err := adminJetStream.CreateKeyValue(ctxFor(t), jetstream.KeyValueConfig{Bucket: "mesh-mail_sends"}); err != nil {
t.Fatalf("the admin could not make the bucket: %v", err)
}
conn, err := Connect(account)
if err != nil {
t.Fatal(err)
}
defer conn.Close()
s := conn.State("sends")
if _, err := s.Put("k", 1); err != nil {
t.Fatal(err)
}
if err := s.Delete("k"); err != nil {
t.Fatalf("Delete on a granted bucket: %v", err)
}
if e, err := s.Get("k"); err != nil || e != nil {
t.Fatalf("Get after Delete: %+v, %v", e, err)
}
if err := s.Delete("k"); err != nil {
t.Fatalf("Delete of an absent key: %v", err)
}
}
+25
View File
@@ -82,6 +82,14 @@ func (f *fakeKV) Put(_ context.Context, key string, value []byte) (uint64, error
return f.next, nil
}
func (f *fakeKV) Delete(_ context.Context, key string, _ ...jetstream.KVDeleteOpt) error {
f.mu.Lock()
defer f.mu.Unlock()
delete(f.values, key)
delete(f.revs, key)
return nil
}
func (f *fakeKV) Keys(_ context.Context, _ ...jetstream.WatchOpt) ([]string, error) {
f.mu.Lock()
defer f.mu.Unlock()
@@ -277,3 +285,20 @@ type silentKV struct{ jetstream.KeyValue }
func (silentKV) Watch(context.Context, string, ...jetstream.WatchOpt) (jetstream.KeyWatcher, error) {
return &fakeWatcher{updates: make(chan jetstream.KeyValueEntry)}, nil
}
// 1840/S1: given a key, when it is deleted, then it reads as absent; deleting a key that was not there is no error.
func TestStateDeleteRemovesAKeyAndAnAbsentOneIsNoError(t *testing.T) {
s := stateOn(newFakeKV())
if _, err := s.Put("k", 1); err != nil {
t.Fatal(err)
}
if err := s.Delete("k"); err != nil {
t.Fatalf("Delete of a key: %v", err)
}
if e, err := s.Get("k"); err != nil || e != nil {
t.Fatalf("Get after Delete: %+v, %v, want absent", e, err)
}
if err := s.Delete("never"); err != nil {
t.Fatalf("Delete of an absent key: %v", err)
}
}