package database import ( "encoding/json" "errors" "testing" "time" kv "git.sr.ht/~ashkeel/kilovolt/v12" ) func TestLocalDBClientPutKey(t *testing.T) { client, store := CreateInMemoryLocalClient(t) defer CleanupLocalClient(client) // Store a key using the local client key := "test" value := "value" err := client.PutKey(key, value) if err != nil { t.Fatal(err) } // Retrieve the key from the store and verify it stored, err := store.Get(key) if err != nil { t.Fatal(err) } if stored != value { t.Fatalf("expected %s, got %s", value, stored) } } func TestLocalDBClientPutJSON(t *testing.T) { client, store := CreateInMemoryLocalClient(t) defer CleanupLocalClient(client) type test struct { A string B int } testStruct := test{ A: "test", B: 42, } // Store a key using the local client key := "test" err := client.PutJSON(key, testStruct) if err != nil { t.Fatal(err) } // Retrieve the key from the store and verify it stored, err := store.Get(key) if err != nil { t.Fatal(err) } var testStored test err = json.Unmarshal([]byte(stored), &testStored) if err != nil { t.Fatal(err) } if testStored.A != testStruct.A { t.Fatalf("expected A to be %s, got %s", testStruct.A, testStored.A) } if testStored.B != testStruct.B { t.Fatalf("expected B to be %d, got %d", testStruct.B, testStored.B) } } func TestLocalDBClientPutJSONBulk(t *testing.T) { client, store := CreateInMemoryLocalClient(t) defer CleanupLocalClient(client) type test struct { A string B int } testA := test{ A: "test", B: 42, } testB := test{ A: "test2", B: 43, } // Store some keys using the local client err := client.PutJSONBulk(map[string]any{ "test": testA, "test2": testB, }) if err != nil { t.Fatal(err) } // Retrieve both keys from the store and verify them keys, err := store.GetBulk([]string{"test", "test2"}) if err != nil { t.Fatal(err) } var testStored1 test err = json.Unmarshal([]byte(keys["test"]), &testStored1) if err != nil { t.Fatal(err) } var testStored2 test err = json.Unmarshal([]byte(keys["test2"]), &testStored2) if err != nil { t.Fatal(err) } if testStored1.A != testA.A { t.Fatalf("expected test A to be %s, got %s", testA.A, testStored1.A) } if testStored1.B != testA.B { t.Fatalf("expected test B to be %d, got %d", testA.B, testStored1.B) } if testStored2.A != testB.A { t.Fatalf("expected test2 A to be %s, got %s", testB.A, testStored2.A) } if testStored2.B != testB.B { t.Fatalf("expected test2 B to be %d, got %d", testB.B, testStored2.B) } } func TestLocalDBClientGetKey(t *testing.T) { client, store := CreateInMemoryLocalClient(t) defer CleanupLocalClient(client) // Store a key directly in the store key := "test" value := "value" err := store.Set(key, value) if err != nil { t.Fatal(err) } // Retrieve the key using the local client stored, err := client.GetKey(key) if err != nil { t.Fatal(err) } if stored != value { t.Fatalf("expected %s, got %s", value, stored) } } func TestLocalDBClientGetJSON(t *testing.T) { client, store := CreateInMemoryLocalClient(t) defer CleanupLocalClient(client) type test struct { A string B int } testStruct := test{ A: "test", B: 42, } // Store a key directly in the store key := "test" byt, err := json.Marshal(testStruct) if err != nil { t.Fatal(err) } err = store.Set(key, string(byt)) if err != nil { t.Fatal(err) } // Retrieve the key using the local client var stored test err = client.GetJSON(key, &stored) if err != nil { t.Fatal(err) } if stored.A != testStruct.A { t.Fatalf("expected A to be %s, got %s", testStruct.A, stored.A) } if stored.B != testStruct.B { t.Fatalf("expected B to be %d, got %d", testStruct.B, stored.B) } } func TestLocalDBClientGetAll(t *testing.T) { client, store := CreateInMemoryLocalClient(t) defer CleanupLocalClient(client) // Store a bunch of keys directly in the store keys := map[string]string{ "test": "value", "test2": "value2", "test3": "value3", } err := store.SetBulk(keys) if err != nil { t.Fatal(err) } // Retrieve the keys using the local client stored, err := client.GetAll("test") if err != nil { t.Fatal(err) } // Verify the correct keys are returned if len(stored) != 3 { t.Fatalf("expected 3 keys, got %d", len(stored)) } for key, value := range keys { storedValue, ok := stored[key] if !ok { t.Errorf("expected key %s to be returned", key) } if storedValue != value { t.Errorf("expected key %s to be %s, got %s", key, value, storedValue) } } } func TestLocalDBClientRemoveKey(t *testing.T) { client, store := CreateInMemoryLocalClient(t) defer CleanupLocalClient(client) // Store a key directly in the store key := "test" err := store.Set(key, "value") if err != nil { t.Fatal(err) } // Remove the key using the local client err = client.RemoveKey(key) if err != nil { t.Fatal(err) } // Verify the key is removed _, err = store.Get(key) if err == nil { t.Fatal("expected key to be removed") } else if !errors.Is(err, kv.ErrorKeyNotFound) { t.Fatalf("expected key to be removed, got %s", err) } } func TestLocalDBClientSubscribeKey(t *testing.T) { client, _ := CreateInMemoryLocalClient(t) defer CleanupLocalClient(client) // Subscribe to a key using the local client key := "test" ch := make(chan string, 1) cancel, err := client.SubscribeKey(key, func(newValue string) { ch <- newValue }) if err != nil { t.Fatal(err) } defer cancel() // Store a key err = client.PutKey(key, "value") if err != nil { t.Fatal(err) } select { case newValue := <-ch: if newValue != "value" { t.Fatalf("expected value to be %s, got %s", "value", newValue) } case <-time.After(time.Second * 2): t.Fatal("expected value to be received") } } func TestLocalDBClientSubscribePrefix(t *testing.T) { client, _ := CreateInMemoryLocalClient(t) defer CleanupLocalClient(client) // Subscribe to a prefix using the local client prefix := "test" ch := make(chan string, 1) cancel, err := client.SubscribePrefix(func(_, newValue string) { ch <- newValue }, prefix) if err != nil { t.Fatal(err) } defer cancel() // Write a key err = client.PutKey("testWithStuff", "value") if err != nil { t.Fatal(err) } select { case newValue := <-ch: if newValue != "value" { t.Fatalf("expected value to be %s, got %s", "value", newValue) } case <-time.After(time.Second * 2): t.Fatal("expected value to be received") } }