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