joist/internal/badger_test.go
2025-08-31 06:41:53 -04:00

188 lines
3.9 KiB
Go

package internal
import (
"context"
"os"
"path/filepath"
"testing"
"time"
)
func newTestStore(t *testing.T) *badgerStore {
t.Helper()
dir := filepath.Join(os.TempDir(), "badger_test", time.Now().Format("20060102150405"))
store, err := NewBadgerStore(WithBaseDir(dir))
if err != nil {
t.Fatalf("failed to create store: %v", err)
}
t.Cleanup(func() {
store.Close()
os.RemoveAll(dir)
})
return store
}
// generic subtest runner
type subtest struct {
name string
run func(t *testing.T)
}
func runSubtests(t *testing.T, subs []subtest) {
for _, st := range subs {
t.Run(st.name, st.run)
}
}
func TestBadgerStore(t *testing.T) {
tests := []struct {
name string
test func(t *testing.T, store *badgerStore)
}{
{
name: "Put/Get/Delete roundtrip",
test: func(t *testing.T, store *badgerStore) {
ctx := context.Background()
key := "foo"
val := []byte("bar")
runSubtests(t, []subtest{
{
name: "Put",
run: func(t *testing.T) {
if err := store.Put(ctx, key, val, time.Minute); err != nil {
t.Fatalf("Put failed: %v", err)
}
},
},
{
name: "Get",
run: func(t *testing.T) {
got, err := store.Get(ctx, key)
if err != nil {
t.Fatalf("Get failed: %v", err)
}
if string(got) != string(val) {
t.Errorf("Get returned %q, want %q", got, val)
}
},
},
{
name: "Delete",
run: func(t *testing.T) {
if err := store.Delete(ctx, key); err != nil {
t.Fatalf("Delete failed: %v", err)
}
},
},
{
name: "Get after delete",
run: func(t *testing.T) {
_, err := store.Get(ctx, key)
if err == nil {
t.Errorf("expected error after delete, got nil")
}
},
},
})
},
},
{
name: "PutWithTTL expires",
test: func(t *testing.T, store *badgerStore) {
ctx := context.Background()
key := "ttl"
val := []byte("value")
if err := store.Put(ctx, key, val, time.Second); err != nil {
t.Fatalf("Put failed: %v", err)
}
// Should exist immediately
if _, err := store.Get(ctx, key); err != nil {
t.Fatalf("Get failed immediately: %v", err)
}
// Wait for TTL
time.Sleep(2 * time.Second)
_, err := store.Get(ctx, key)
if err == nil {
t.Errorf("expected error after TTL expiry, got nil")
}
},
},
{
name: "ContextCancellation affects operations",
test: func(t *testing.T, store *badgerStore) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
runSubtests(t, []subtest{
{
name: "Put fails",
run: func(t *testing.T) {
if err := store.Put(ctx, "x", []byte("y"), time.Minute); err == nil {
t.Errorf("expected Put to fail with canceled context")
}
},
},
{
name: "Get fails",
run: func(t *testing.T) {
if _, err := store.Get(ctx, "x"); err == nil {
t.Errorf("expected Get to fail with canceled context")
}
},
},
{
name: "Delete fails",
run: func(t *testing.T) {
if err := store.Delete(ctx, "x"); err == nil {
t.Errorf("expected Delete to fail with canceled context")
}
},
},
})
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
store := newTestStore(t)
tt.test(t, store)
})
}
}
func TestDirFunction(t *testing.T) {
tests := []struct {
name string
store *badgerStore
want string
}{
{
name: "default directory",
store: &badgerStore{},
want: defaultBaseDir,
},
{
name: "with base and sub dir",
store: &badgerStore{baseDir: "/tmp", subDir: "foo"},
want: filepath.Join("/tmp", "foo"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.store.dir(); got != tt.want {
t.Errorf("expected dir %q, got %q", tt.want, got)
}
})
}
}