github.com/nutsdb/nutsdb@v1.0.4/btree_test.go (about) 1 // Copyright 2023 The nutsdb Author. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package nutsdb 16 17 import ( 18 "fmt" 19 "github.com/stretchr/testify/assert" 20 "github.com/stretchr/testify/require" 21 "testing" 22 ) 23 24 var ( 25 keyFormat = "key_%03d" 26 valFormat = "val_%03d" 27 ) 28 29 func runBTreeTest(t *testing.T, test func(t *testing.T, btree *BTree)) { 30 btree := NewBTree() 31 32 for i := 0; i < 100; i++ { 33 key := []byte(fmt.Sprintf(keyFormat, i)) 34 val := []byte(fmt.Sprintf(valFormat, i)) 35 36 _ = btree.Insert(NewRecord().WithKey(key).WithValue(val)) 37 } 38 39 test(t, btree) 40 } 41 42 func TestBTree_Find(t *testing.T) { 43 runBTreeTest(t, func(t *testing.T, btree *BTree) { 44 r, ok := btree.Find([]byte(fmt.Sprintf(keyFormat, 0))) 45 require.Equal(t, []byte(fmt.Sprintf(keyFormat, 0)), r.Key) 46 require.True(t, ok) 47 }) 48 } 49 50 func TestBTree_Delete(t *testing.T) { 51 runBTreeTest(t, func(t *testing.T, btree *BTree) { 52 require.True(t, btree.Delete([]byte(fmt.Sprintf(keyFormat, 0)))) 53 require.False(t, btree.Delete([]byte(fmt.Sprintf(keyFormat, 100)))) 54 55 _, ok := btree.Find([]byte(fmt.Sprintf(keyFormat, 0))) 56 require.False(t, ok) 57 }) 58 } 59 60 func TestBTree_PrefixScan(t *testing.T) { 61 t.Run("prefix scan from beginning", func(t *testing.T) { 62 runBTreeTest(t, func(t *testing.T, btree *BTree) { 63 limit := 10 64 65 records := btree.PrefixScan([]byte("key_"), 0, limit) 66 67 for i, r := range records { 68 wantKey := []byte(fmt.Sprintf(keyFormat, i)) 69 wantValue := []byte(fmt.Sprintf(valFormat, i)) 70 71 assert.Equal(t, wantKey, r.Key) 72 assert.Equal(t, wantValue, r.Value) 73 } 74 }) 75 }) 76 77 t.Run("prefix scan for not exists pre key", func(t *testing.T) { 78 runBTreeTest(t, func(t *testing.T, btree *BTree) { 79 records := btree.PrefixScan([]byte("key_xx"), 0, 10) 80 assert.Len(t, records, 0) 81 }) 82 }) 83 } 84 85 func TestBTree_PrefixSearchScan(t *testing.T) { 86 t.Run("prefix search scan right email", func(t *testing.T) { 87 runBTreeTest(t, func(t *testing.T, btree *BTree) { 88 89 key := []byte("nutsdb-123456789@outlook.com") 90 val := GetRandomBytes(24) 91 92 _ = btree.Insert(NewRecord().WithKey(key).WithValue(val)) 93 94 record, ok := btree.Find(key) 95 require.True(t, ok) 96 require.Equal(t, key, record.Key) 97 98 records := btree.PrefixSearchScan([]byte("nutsdb-"), 99 "[a-z\\d]+(\\.[a-z\\d]+)*@([\\da-z](-[\\da-z])?)+(\\.{1,2}[a-z]+)+$", 0, 1) 100 require.Equal(t, key, records[0].Key) 101 }) 102 }) 103 104 t.Run("prefix search scan wrong email", func(t *testing.T) { 105 runBTreeTest(t, func(t *testing.T, btree *BTree) { 106 107 key := []byte("nutsdb-123456789@outlook") 108 val := GetRandomBytes(24) 109 110 _ = btree.Insert(NewRecord().WithKey(key).WithValue(val)) 111 112 record, ok := btree.Find(key) 113 require.True(t, ok) 114 require.Equal(t, key, record.Key) 115 116 records := btree.PrefixSearchScan([]byte("nutsdb-"), 117 "[a-z\\d]+(\\.[a-z\\d]+)*@([\\da-z](-[\\da-z])?)+(\\.{1,2}[a-z]+)+$", 0, 1) 118 require.Len(t, records, 0) 119 }) 120 }) 121 } 122 123 func TestBTree_All(t *testing.T) { 124 runBTreeTest(t, func(t *testing.T, btree *BTree) { 125 expectRecords := make([]*Record, 100) 126 127 for i := 0; i < 100; i++ { 128 key := []byte(fmt.Sprintf(keyFormat, i)) 129 val := []byte(fmt.Sprintf(valFormat, i)) 130 131 expectRecords[i] = NewRecord().WithKey(key).WithValue(val) 132 } 133 134 require.ElementsMatch(t, expectRecords, btree.All()) 135 }) 136 } 137 138 func TestBTree_Range(t *testing.T) { 139 t.Run("btree range at begin", func(t *testing.T) { 140 runBTreeTest(t, func(t *testing.T, btree *BTree) { 141 expectRecords := make([]*Record, 10) 142 143 for i := 0; i < 10; i++ { 144 key := []byte(fmt.Sprintf(keyFormat, i)) 145 val := []byte(fmt.Sprintf(valFormat, i)) 146 147 expectRecords[i] = NewRecord().WithKey(key).WithValue(val) 148 } 149 150 records := btree.Range([]byte(fmt.Sprintf(keyFormat, 0)), []byte(fmt.Sprintf(keyFormat, 9))) 151 152 require.ElementsMatch(t, records, expectRecords) 153 }) 154 }) 155 156 t.Run("btree range at middle", func(t *testing.T) { 157 runBTreeTest(t, func(t *testing.T, btree *BTree) { 158 expectRecords := make([]*Record, 10) 159 160 for i := 40; i < 50; i++ { 161 key := []byte(fmt.Sprintf(keyFormat, i)) 162 val := []byte(fmt.Sprintf(valFormat, i)) 163 164 expectRecords[i-40] = NewRecord().WithKey(key).WithValue(val) 165 } 166 167 records := btree.Range([]byte(fmt.Sprintf(keyFormat, 40)), []byte(fmt.Sprintf(keyFormat, 49))) 168 169 require.ElementsMatch(t, records, expectRecords) 170 }) 171 }) 172 173 t.Run("btree range at end", func(t *testing.T) { 174 runBTreeTest(t, func(t *testing.T, btree *BTree) { 175 expectRecords := make([]*Record, 10) 176 177 for i := 90; i < 100; i++ { 178 key := []byte(fmt.Sprintf(keyFormat, i)) 179 val := []byte(fmt.Sprintf(valFormat, i)) 180 181 expectRecords[i-90] = NewRecord().WithKey(key).WithValue(val) 182 } 183 184 records := btree.Range([]byte(fmt.Sprintf(keyFormat, 90)), []byte(fmt.Sprintf(keyFormat, 99))) 185 186 require.ElementsMatch(t, records, expectRecords) 187 }) 188 }) 189 } 190 191 func TestBTree_Update(t *testing.T) { 192 runBTreeTest(t, func(t *testing.T, btree *BTree) { 193 for i := 40; i < 50; i++ { 194 key := []byte(fmt.Sprintf(keyFormat, i)) 195 val := []byte(fmt.Sprintf("val_%03d_modify", i)) 196 197 btree.Insert(NewRecord().WithKey(key).WithValue(val)) 198 } 199 200 records := btree.Range([]byte(fmt.Sprintf(keyFormat, 40)), []byte(fmt.Sprintf(keyFormat, 49))) 201 202 for i := 40; i < 50; i++ { 203 require.Equal(t, []byte(fmt.Sprintf("val_%03d_modify", i)), records[i-40].Value) 204 } 205 }) 206 }