package db import ( "path" "sync" "testing" ) // TestKVInc tests that the KVInc function behaves correctly under concurrent access func TestKVInc(t *testing.T) { posternDB, err := OpenDB(&Config{ DBPath: path.Join(t.TempDir(), "meta.db"), }) if err != nil { t.Fatal(err) } defer func(posternDB *DB) { err := posternDB.Close() if err != nil { t.Fatal(err) } }(posternDB) key := "test-concurrency-key" if err := posternDB.KVSet(t.Context(), key, 0); err != nil { t.Fatalf("KVSet setup failed: %v", err) } const numGoroutines = 50 const incsPerGoroutine = 200 var wg sync.WaitGroup wg.Add(numGoroutines) for range numGoroutines { go func(db *DB) { defer wg.Done() for range incsPerGoroutine { _, err := db.KVInc(t.Context(), key, 1) if err != nil { t.Errorf("KVInc failed during execution: %v", err) return } } }(posternDB) } wg.Wait() // Retrieve the final count val, err := posternDB.KVGet(t.Context(), key) if err != nil { t.Fatalf("KVGet failed to fetch final value: %v", err) } got, ok := val.(int64) if !ok { t.Fatalf("KVGet returned unexpected type: %T, expected int", val) } // Catch race conditions expected := int64(numGoroutines * incsPerGoroutine) if got != expected { t.Errorf("Race condition detected! Expected final value %d, got %d", expected, got) } // Check return value of next increment res, err := posternDB.KVInc(t.Context(), key, 1) if err != nil { t.Errorf("KVInc failed during execution: %v", err) return } if res != expected+1 { t.Errorf("Incrementation mismatch! Expected final value %d, got %d", expected+1, res) } } // TestKVList tests that the KVList function returns all stored key value pairs func TestKVList(t *testing.T) { posternDB, err := OpenDB(&Config{ DBPath: path.Join(t.TempDir(), "meta.db"), }) if err != nil { t.Fatal(err) } defer func(posternDB *DB) { err := posternDB.Close() if err != nil { t.Fatal(err) } }(posternDB) want := map[string]any{ "key-1": "value-1", "key-2": int64(42), } for key, val := range want { if err := posternDB.KVSet(t.Context(), key, val); err != nil { t.Fatalf("KVSet setup failed: %v", err) } } got, err := posternDB.KVList(t.Context()) if err != nil { t.Fatalf("KVList failed: %v", err) } if len(got) != len(want) { t.Fatalf("Expected %d pairs, got %d", len(want), len(got)) } for key, expected := range want { val, ok := got[key] if !ok { t.Errorf("Missing key %q in KVList result", key) continue } if val != expected { t.Errorf("Key %q: expected value %v, got %v", key, expected, val) } } } // TestKVIncString tests that the KVInc function does not increment invalid values func TestKVIncString(t *testing.T) { posternDB, err := OpenDB(&Config{ DBPath: path.Join(t.TempDir(), "meta.db"), }) if err != nil { t.Fatal(err) } defer func(posternDB *DB) { err := posternDB.Close() if err != nil { t.Fatal(err) } }(posternDB) key := "test-key" if err := posternDB.KVSet(t.Context(), key, "value"); err != nil { t.Fatalf("KVSet setup failed: %v", err) } _, err = posternDB.KVInc(t.Context(), key, 1) if err == nil { t.Fatalf("KVInc should have failed during execution due to attempt incrementing a non-integer value") } } // TestKVDelete tests the KVDelete function func TestKVDelete(t *testing.T) { posternDB, err := OpenDB(&Config{ DBPath: path.Join(t.TempDir(), "meta.db"), }) if err != nil { t.Fatal(err) } defer func(posternDB *DB) { err := posternDB.Close() if err != nil { t.Fatal(err) } }(posternDB) key := "test-key" var testVal int64 = 42 if err := posternDB.KVSet(t.Context(), key, testVal); err != nil { t.Fatalf("KVSet setup failed: %v", err) } val, err := posternDB.KVPop(t.Context(), key) if err != nil { t.Fatalf("KVGet failed to fetch final value: %v", err) } if val != testVal { t.Errorf("Expected value %d, got %d", testVal, val) } _, err = posternDB.KVPop(t.Context(), key) if err == nil { t.Fatalf("KVDelete should have failed during execution due to missing key") } }