this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add duckdb tests for kvstore

Paul Frazee eebe95da dfa26d04

+228
+228
cmd/butterfly/store/duckdb_test.go
··· 4 4 "context" 5 5 "fmt" 6 6 "path/filepath" 7 + "strings" 8 + "sync" 7 9 "testing" 8 10 "time" 9 11 ··· 777 779 require.NoError(t, err) 778 780 assert.Len(t, posts, 0) 779 781 } 782 + 783 + func TestDuckdbStore_KvStore_BasicOperations(t *testing.T) { 784 + tmpDir := t.TempDir() 785 + dbPath := filepath.Join(tmpDir, "test.db") 786 + store := NewDuckdbStore(dbPath) 787 + 788 + ctx := context.Background() 789 + err := store.Setup(ctx) 790 + require.NoError(t, err) 791 + defer store.Close() 792 + 793 + // Test Put and Get 794 + err = store.KvPut("namespace1", "key1", "value1") 795 + require.NoError(t, err) 796 + 797 + value, err := store.KvGet("namespace1", "key1") 798 + require.NoError(t, err) 799 + assert.Equal(t, "value1", value) 800 + 801 + // Test updating existing key 802 + err = store.KvPut("namespace1", "key1", "updated_value1") 803 + require.NoError(t, err) 804 + 805 + value, err = store.KvGet("namespace1", "key1") 806 + require.NoError(t, err) 807 + assert.Equal(t, "updated_value1", value) 808 + 809 + // Test different namespace 810 + err = store.KvPut("namespace2", "key1", "value2") 811 + require.NoError(t, err) 812 + 813 + value, err = store.KvGet("namespace2", "key1") 814 + require.NoError(t, err) 815 + assert.Equal(t, "value2", value) 816 + 817 + // Verify namespace isolation 818 + value, err = store.KvGet("namespace1", "key1") 819 + require.NoError(t, err) 820 + assert.Equal(t, "updated_value1", value) 821 + } 822 + 823 + func TestDuckdbStore_KvStore_GetNonExistent(t *testing.T) { 824 + tmpDir := t.TempDir() 825 + dbPath := filepath.Join(tmpDir, "test.db") 826 + store := NewDuckdbStore(dbPath) 827 + 828 + ctx := context.Background() 829 + err := store.Setup(ctx) 830 + require.NoError(t, err) 831 + defer store.Close() 832 + 833 + // Test get non-existent key 834 + _, err = store.KvGet("namespace1", "nonexistent") 835 + require.Error(t, err) 836 + assert.Contains(t, err.Error(), "not found") 837 + 838 + // Test get from non-existent namespace 839 + _, err = store.KvGet("nonexistent_namespace", "key1") 840 + require.Error(t, err) 841 + assert.Contains(t, err.Error(), "not found") 842 + } 843 + 844 + func TestDuckdbStore_KvStore_Delete(t *testing.T) { 845 + tmpDir := t.TempDir() 846 + dbPath := filepath.Join(tmpDir, "test.db") 847 + store := NewDuckdbStore(dbPath) 848 + 849 + ctx := context.Background() 850 + err := store.Setup(ctx) 851 + require.NoError(t, err) 852 + defer store.Close() 853 + 854 + // Put a value 855 + err = store.KvPut("namespace1", "key1", "value1") 856 + require.NoError(t, err) 857 + 858 + // Verify it exists 859 + value, err := store.KvGet("namespace1", "key1") 860 + require.NoError(t, err) 861 + assert.Equal(t, "value1", value) 862 + 863 + // Delete it 864 + err = store.KvDel("namespace1", "key1") 865 + require.NoError(t, err) 866 + 867 + // Verify it's gone 868 + _, err = store.KvGet("namespace1", "key1") 869 + require.Error(t, err) 870 + assert.Contains(t, err.Error(), "not found") 871 + 872 + // Delete non-existent key should not error 873 + err = store.KvDel("namespace1", "nonexistent") 874 + require.NoError(t, err) 875 + 876 + // Delete from non-existent namespace should not error 877 + err = store.KvDel("nonexistent_namespace", "key1") 878 + require.NoError(t, err) 879 + } 880 + 881 + func TestDuckdbStore_KvStore_SpecialCharacters(t *testing.T) { 882 + tmpDir := t.TempDir() 883 + dbPath := filepath.Join(tmpDir, "test.db") 884 + store := NewDuckdbStore(dbPath) 885 + 886 + ctx := context.Background() 887 + err := store.Setup(ctx) 888 + require.NoError(t, err) 889 + defer store.Close() 890 + 891 + // Test with special characters in namespace, key, and value 892 + specialNamespace := "namespace:with:colons" 893 + specialKey := "key/with/slashes" 894 + specialValue := `{"json": "value", "with": "quotes 'and' \"escapes\"", "newline": "test\nvalue"}` 895 + 896 + err = store.KvPut(specialNamespace, specialKey, specialValue) 897 + require.NoError(t, err) 898 + 899 + value, err := store.KvGet(specialNamespace, specialKey) 900 + require.NoError(t, err) 901 + assert.Equal(t, specialValue, value) 902 + 903 + // Test with empty string value 904 + err = store.KvPut("namespace1", "emptykey", "") 905 + require.NoError(t, err) 906 + 907 + value, err = store.KvGet("namespace1", "emptykey") 908 + require.NoError(t, err) 909 + assert.Equal(t, "", value) 910 + } 911 + 912 + func TestDuckdbStore_KvStore_LargeValues(t *testing.T) { 913 + tmpDir := t.TempDir() 914 + dbPath := filepath.Join(tmpDir, "test.db") 915 + store := NewDuckdbStore(dbPath) 916 + 917 + ctx := context.Background() 918 + err := store.Setup(ctx) 919 + require.NoError(t, err) 920 + defer store.Close() 921 + 922 + // Test with large value (1MB) 923 + largeValue := strings.Repeat("a", 1024*1024) 924 + 925 + err = store.KvPut("namespace1", "largekey", largeValue) 926 + require.NoError(t, err) 927 + 928 + value, err := store.KvGet("namespace1", "largekey") 929 + require.NoError(t, err) 930 + assert.Equal(t, largeValue, value) 931 + } 932 + 933 + func TestDuckdbStore_KvStore_Persistence(t *testing.T) { 934 + tmpDir := t.TempDir() 935 + dbPath := filepath.Join(tmpDir, "test.db") 936 + 937 + // Create store and add data 938 + store1 := NewDuckdbStore(dbPath) 939 + ctx := context.Background() 940 + err := store1.Setup(ctx) 941 + require.NoError(t, err) 942 + 943 + err = store1.KvPut("namespace1", "key1", "value1") 944 + require.NoError(t, err) 945 + err = store1.KvPut("namespace2", "key2", "value2") 946 + require.NoError(t, err) 947 + 948 + store1.Close() 949 + 950 + // Create new store instance with same DB path 951 + store2 := NewDuckdbStore(dbPath) 952 + err = store2.Setup(ctx) 953 + require.NoError(t, err) 954 + defer store2.Close() 955 + 956 + // Verify data persisted 957 + value, err := store2.KvGet("namespace1", "key1") 958 + require.NoError(t, err) 959 + assert.Equal(t, "value1", value) 960 + 961 + value, err = store2.KvGet("namespace2", "key2") 962 + require.NoError(t, err) 963 + assert.Equal(t, "value2", value) 964 + } 965 + 966 + func TestDuckdbStore_KvStore_ConcurrentAccess(t *testing.T) { 967 + tmpDir := t.TempDir() 968 + dbPath := filepath.Join(tmpDir, "test.db") 969 + store := NewDuckdbStore(dbPath) 970 + 971 + ctx := context.Background() 972 + err := store.Setup(ctx) 973 + require.NoError(t, err) 974 + defer store.Close() 975 + 976 + // Test concurrent writes to different keys 977 + var wg sync.WaitGroup 978 + numGoroutines := 10 979 + numOperations := 100 980 + 981 + for i := 0; i < numGoroutines; i++ { 982 + wg.Add(1) 983 + go func(goroutineID int) { 984 + defer wg.Done() 985 + for j := 0; j < numOperations; j++ { 986 + key := fmt.Sprintf("key_%d_%d", goroutineID, j) 987 + value := fmt.Sprintf("value_%d_%d", goroutineID, j) 988 + err := store.KvPut("concurrent_namespace", key, value) 989 + assert.NoError(t, err) 990 + } 991 + }(i) 992 + } 993 + 994 + wg.Wait() 995 + 996 + // Verify all values were written correctly 997 + for i := 0; i < numGoroutines; i++ { 998 + for j := 0; j < numOperations; j++ { 999 + key := fmt.Sprintf("key_%d_%d", i, j) 1000 + expectedValue := fmt.Sprintf("value_%d_%d", i, j) 1001 + 1002 + value, err := store.KvGet("concurrent_namespace", key) 1003 + require.NoError(t, err) 1004 + assert.Equal(t, expectedValue, value) 1005 + } 1006 + } 1007 + }