github.com/iotexproject/iotex-core@v1.14.1-rc1/db/db_test.go (about) 1 // Copyright (c) 2019 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package db 7 8 import ( 9 "bytes" 10 "context" 11 "testing" 12 13 "github.com/pkg/errors" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 17 "github.com/iotexproject/go-pkgs/hash" 18 19 "github.com/iotexproject/iotex-core/db/batch" 20 "github.com/iotexproject/iotex-core/pkg/util/byteutil" 21 "github.com/iotexproject/iotex-core/testutil" 22 ) 23 24 var ( 25 _bucket1 = "test_ns1" 26 _bucket2 = "test_ns2" 27 _testK1 = [3][]byte{[]byte("key_1"), []byte("key_2"), []byte("key_3")} 28 _testV1 = [3][]byte{[]byte("value_1"), []byte("value_2"), []byte("value_3")} 29 _testK2 = [3][]byte{[]byte("key_4"), []byte("key_5"), []byte("key_6")} 30 _testV2 = [3][]byte{[]byte("value_4"), []byte("value_5"), []byte("value_6")} 31 ) 32 33 func TestKVStorePutGet(t *testing.T) { 34 testKVStorePutGet := func(kvStore KVStore, t *testing.T) { 35 assert := assert.New(t) 36 ctx := context.Background() 37 38 assert.Nil(kvStore.Start(ctx)) 39 defer func() { 40 err := kvStore.Stop(ctx) 41 assert.Nil(err) 42 }() 43 44 assert.Nil(kvStore.Put(_bucket1, []byte("key"), []byte("value"))) 45 value, err := kvStore.Get(_bucket1, []byte("key")) 46 assert.Nil(err) 47 assert.Equal([]byte("value"), value) 48 value, err = kvStore.Get("test_ns_1", []byte("key")) 49 assert.NotNil(err) 50 assert.Nil(value) 51 value, err = kvStore.Get(_bucket1, _testK1[0]) 52 assert.NotNil(err) 53 assert.Nil(value) 54 } 55 56 path := "test-kv-store.bolt" 57 testPath, err := testutil.PathOfTempFile(path) 58 require.NoError(t, err) 59 defer testutil.CleanupPath(testPath) 60 cfg := DefaultConfig 61 cfg.DbPath = testPath 62 63 for _, v := range []KVStore{ 64 NewMemKVStore(), 65 NewBoltDB(cfg), 66 } { 67 t.Run("test put get", func(t *testing.T) { 68 testKVStorePutGet(v, t) 69 }) 70 } 71 72 } 73 74 func TestBatchRollback(t *testing.T) { 75 testBatchRollback := func(kvStore KVStore, t *testing.T) { 76 assert := assert.New(t) 77 ctx := context.Background() 78 79 assert.Nil(kvStore.Start(ctx)) 80 defer func() { 81 err := kvStore.Stop(ctx) 82 assert.Nil(err) 83 }() 84 85 assert.Nil(kvStore.Put(_bucket1, _testK1[0], _testV1[0])) 86 value, err := kvStore.Get(_bucket1, _testK1[0]) 87 assert.Nil(err) 88 assert.Equal(_testV1[0], value) 89 assert.Nil(kvStore.Put(_bucket1, _testK1[1], _testV1[1])) 90 value, err = kvStore.Get(_bucket1, _testK1[1]) 91 assert.Nil(err) 92 assert.Equal(_testV1[1], value) 93 assert.Nil(kvStore.Put(_bucket1, _testK1[2], _testV1[2])) 94 value, err = kvStore.Get(_bucket1, _testK1[2]) 95 assert.Nil(err) 96 assert.Equal(_testV1[2], value) 97 98 testV := [3][]byte{[]byte("value1.1"), []byte("value2.1"), []byte("value3.1")} 99 kvboltDB := kvStore.(*BoltDB) 100 err = kvboltDB.batchPutForceFail(_bucket1, _testK1[:], testV[:]) 101 assert.NotNil(err) 102 103 value, err = kvStore.Get(_bucket1, _testK1[0]) 104 assert.Nil(err) 105 assert.Equal(_testV1[0], value) 106 value, err = kvStore.Get(_bucket1, _testK1[1]) 107 assert.Nil(err) 108 assert.Equal(_testV1[1], value) 109 value, err = kvStore.Get(_bucket1, _testK1[2]) 110 assert.Nil(err) 111 assert.Equal(_testV1[2], value) 112 } 113 114 path := "test-batch-rollback.bolt" 115 testPath, err := testutil.PathOfTempFile(path) 116 require.NoError(t, err) 117 defer testutil.CleanupPath(testPath) 118 cfg := DefaultConfig 119 cfg.DbPath = testPath 120 121 t.Run("test rollback", func(t *testing.T) { 122 testBatchRollback(NewBoltDB(cfg), t) 123 }) 124 125 } 126 127 func TestDBInMemBatchCommit(t *testing.T) { 128 require := require.New(t) 129 kvStore := NewMemKVStore() 130 ctx := context.Background() 131 b := batch.NewBatch() 132 133 require.NoError(kvStore.Start(ctx)) 134 defer func() { 135 require.NoError(kvStore.Stop(ctx)) 136 }() 137 138 require.NoError(kvStore.Put(_bucket1, _testK1[0], _testV1[1])) 139 require.NoError(kvStore.Put(_bucket2, _testK2[1], _testV2[0])) 140 require.NoError(kvStore.Put(_bucket1, _testK1[2], _testV1[0])) 141 b.Put(_bucket1, _testK1[0], _testV1[0], "") 142 value, err := kvStore.Get(_bucket1, _testK1[0]) 143 require.NoError(err) 144 require.Equal(_testV1[1], value) 145 value, err = kvStore.Get(_bucket2, _testK2[1]) 146 require.NoError(err) 147 require.Equal(_testV2[0], value) 148 require.NoError(kvStore.WriteBatch(b)) 149 value, err = kvStore.Get(_bucket1, _testK1[0]) 150 require.NoError(err) 151 require.Equal(_testV1[0], value) 152 } 153 154 func TestDBBatch(t *testing.T) { 155 testBatchRollback := func(kvStore KVStore, t *testing.T) { 156 require := require.New(t) 157 ctx := context.Background() 158 batch := batch.NewBatch() 159 160 require.NoError(kvStore.Start(ctx)) 161 defer func() { 162 require.NoError(kvStore.Stop(ctx)) 163 }() 164 165 require.NoError(kvStore.Put(_bucket1, _testK1[0], _testV1[1])) 166 require.NoError(kvStore.Put(_bucket2, _testK2[1], _testV2[0])) 167 require.NoError(kvStore.Put(_bucket1, _testK1[2], _testV1[0])) 168 169 batch.Put(_bucket1, _testK1[0], _testV1[0], "") 170 batch.Put(_bucket2, _testK2[1], _testV2[1], "") 171 value, err := kvStore.Get(_bucket1, _testK1[0]) 172 require.NoError(err) 173 require.Equal(_testV1[1], value) 174 175 value, err = kvStore.Get(_bucket2, _testK2[1]) 176 require.NoError(err) 177 require.Equal(_testV2[0], value) 178 require.NoError(kvStore.WriteBatch(batch)) 179 batch.Clear() 180 181 value, err = kvStore.Get(_bucket1, _testK1[0]) 182 require.NoError(err) 183 require.Equal(_testV1[0], value) 184 185 value, err = kvStore.Get(_bucket2, _testK2[1]) 186 require.NoError(err) 187 require.Equal(_testV2[1], value) 188 189 value, err = kvStore.Get(_bucket1, _testK1[2]) 190 require.NoError(err) 191 require.Equal(_testV1[0], value) 192 193 batch.Put(_bucket1, _testK1[0], _testV1[1], "") 194 require.NoError(kvStore.WriteBatch(batch)) 195 batch.Clear() 196 197 require.Equal(0, batch.Size()) 198 199 value, err = kvStore.Get(_bucket2, _testK2[1]) 200 require.NoError(err) 201 require.Equal(_testV2[1], value) 202 203 value, err = kvStore.Get(_bucket1, _testK1[0]) 204 require.NoError(err) 205 require.Equal(_testV1[1], value) 206 207 require.NoError(kvStore.WriteBatch(batch)) 208 batch.Clear() 209 210 batch.Put(_bucket1, _testK1[2], _testV1[2], "") 211 require.NoError(kvStore.WriteBatch(batch)) 212 batch.Clear() 213 214 value, err = kvStore.Get(_bucket1, _testK1[2]) 215 require.NoError(err) 216 require.Equal(_testV1[2], value) 217 218 value, err = kvStore.Get(_bucket2, _testK2[1]) 219 require.NoError(err) 220 require.Equal(_testV2[1], value) 221 222 batch.Clear() 223 batch.Put(_bucket1, _testK1[2], _testV1[2], "") 224 batch.Delete(_bucket2, _testK2[1], "") 225 require.NoError(kvStore.WriteBatch(batch)) 226 batch.Clear() 227 228 value, err = kvStore.Get(_bucket1, _testK1[2]) 229 require.NoError(err) 230 require.Equal(_testV1[2], value) 231 232 _, err = kvStore.Get(_bucket2, _testK2[1]) 233 require.Error(err) 234 } 235 236 path := "test-batch-commit.bolt" 237 testPath, err := testutil.PathOfTempFile(path) 238 require.NoError(t, err) 239 defer testutil.CleanupPath(testPath) 240 cfg := DefaultConfig 241 cfg.DbPath = testPath 242 243 for _, v := range []KVStore{ 244 NewMemKVStore(), 245 NewBoltDB(cfg), 246 } { 247 t.Run("test batch", func(t *testing.T) { 248 testBatchRollback(v, t) 249 }) 250 } 251 } 252 253 func TestCacheKV(t *testing.T) { 254 testFunc := func(kv KVStore, t *testing.T) { 255 require := require.New(t) 256 257 require.NoError(kv.Start(context.Background())) 258 defer func() { 259 require.NoError(kv.Stop(context.Background())) 260 }() 261 262 cb := batch.NewCachedBatch() 263 cb.Put(_bucket1, _testK1[0], _testV1[0], "") 264 v, _ := cb.Get(_bucket1, _testK1[0]) 265 require.Equal(_testV1[0], v) 266 cb.Clear() 267 require.Equal(0, cb.Size()) 268 _, err := cb.Get(_bucket1, _testK1[0]) 269 require.Error(err) 270 cb.Put(_bucket2, _testK2[2], _testV2[2], "") 271 v, _ = cb.Get(_bucket2, _testK2[2]) 272 require.Equal(_testV2[2], v) 273 // put _testK1[1] with a new value 274 cb.Put(_bucket1, _testK1[1], _testV1[2], "") 275 v, _ = cb.Get(_bucket1, _testK1[1]) 276 require.Equal(_testV1[2], v) 277 // delete a non-existing entry is OK 278 cb.Delete(_bucket2, []byte("notexist"), "") 279 require.NoError(kv.WriteBatch(cb)) 280 281 v, _ = kv.Get(_bucket1, _testK1[1]) 282 require.Equal(_testV1[2], v) 283 284 cb = batch.NewCachedBatch() 285 require.NoError(kv.WriteBatch(cb)) 286 } 287 288 path := "test-cache-kv.bolt" 289 testPath, err := testutil.PathOfTempFile(path) 290 require.NoError(t, err) 291 defer testutil.CleanupPath(testPath) 292 cfg := DefaultConfig 293 cfg.DbPath = testPath 294 295 for _, v := range []KVStore{ 296 NewMemKVStore(), 297 NewBoltDB(cfg), 298 } { 299 t.Run("test cache kv", func(t *testing.T) { 300 testFunc(v, t) 301 }) 302 } 303 } 304 305 func TestDeleteBucket(t *testing.T) { 306 testFunc := func(kv KVStore, t *testing.T) { 307 require := require.New(t) 308 309 require.NoError(kv.Start(context.Background())) 310 defer func() { 311 require.NoError(kv.Stop(context.Background())) 312 }() 313 314 require.NoError(kv.Put(_bucket1, _testK1[0], _testV1[0])) 315 v, err := kv.Get(_bucket1, _testK1[0]) 316 require.NoError(err) 317 require.Equal(_testV1[0], v) 318 319 require.NoError(kv.Put(_bucket2, _testK1[0], _testV1[0])) 320 v, err = kv.Get(_bucket2, _testK1[0]) 321 require.NoError(err) 322 require.Equal(_testV1[0], v) 323 324 require.NoError(kv.Delete(_bucket1, nil)) 325 v, err = kv.Get(_bucket1, _testK1[0]) 326 require.Equal(ErrNotExist, errors.Cause(err)) 327 require.Equal([]uint8([]byte(nil)), v) 328 329 v, _ = kv.Get(_bucket2, _testK1[0]) 330 require.Equal(_testV1[0], v) 331 } 332 333 path := "test-delete.bolt" 334 testPath, err := testutil.PathOfTempFile(path) 335 require.NoError(t, err) 336 defer testutil.CleanupPath(testPath) 337 cfg := DefaultConfig 338 cfg.DbPath = testPath 339 340 t.Run("test delete bucket", func(t *testing.T) { 341 testFunc(NewBoltDB(cfg), t) 342 }) 343 } 344 345 func TestFilter(t *testing.T) { 346 require := require.New(t) 347 348 testFunc := func(kv KVStore, t *testing.T) { 349 require.NoError(kv.Start(context.Background())) 350 defer func() { 351 require.NoError(kv.Stop(context.Background())) 352 }() 353 354 tests := []struct { 355 ns string 356 prefix []byte 357 }{ 358 { 359 _bucket1, 360 []byte("test"), 361 }, 362 { 363 _bucket1, 364 []byte("come"), 365 }, 366 { 367 _bucket2, 368 []byte("back"), 369 }, 370 } 371 372 // add 100 keys with each prefix 373 b := batch.NewBatch() 374 numKey := 100 375 for _, e := range tests { 376 for i := 0; i < numKey; i++ { 377 k := append(e.prefix, byteutil.Uint64ToBytesBigEndian(uint64(i))...) 378 v := hash.Hash256b(k) 379 b.Put(e.ns, k, v[:], "") 380 } 381 } 382 require.NoError(kv.WriteBatch(b)) 383 384 _, _, err := kv.Filter("nonamespace", func(k, v []byte) bool { 385 return bytes.HasPrefix(k, v) 386 }, nil, nil) 387 require.Equal(ErrBucketNotExist, errors.Cause(err)) 388 389 // filter using func with no match 390 fk, fv, err := kv.Filter(tests[0].ns, func(k, v []byte) bool { 391 return bytes.HasPrefix(k, tests[2].prefix) 392 }, nil, nil) 393 require.Nil(fk) 394 require.Nil(fv) 395 require.Equal(ErrNotExist, errors.Cause(err)) 396 397 // filter out <k, v> pairs 398 for _, e := range tests { 399 fk, fv, err := kv.Filter(e.ns, func(k, v []byte) bool { 400 return bytes.HasPrefix(k, e.prefix) 401 }, nil, nil) 402 require.NoError(err) 403 require.Equal(numKey, len(fk)) 404 require.Equal(numKey, len(fv)) 405 for i := range fk { 406 k := append(e.prefix, byteutil.Uint64ToBytesBigEndian(uint64(i))...) 407 require.Equal(fk[i], k) 408 v := hash.Hash256b(k) 409 require.Equal(fv[i], v[:]) 410 } 411 } 412 413 // filter with min/max key 414 for _, e := range tests { 415 min := 9 416 max := 91 417 minKey := append(e.prefix, byteutil.Uint64ToBytesBigEndian(uint64(min))...) 418 maxKey := append(e.prefix, byteutil.Uint64ToBytesBigEndian(uint64(max))...) 419 fk, fv, err := kv.Filter(e.ns, func(k, v []byte) bool { 420 return bytes.HasPrefix(k, e.prefix) 421 }, minKey, maxKey) 422 require.NoError(err) 423 require.Equal(max-min+1, len(fk)) 424 require.Equal(max-min+1, len(fv)) 425 for i := range fk { 426 k := append(e.prefix, byteutil.Uint64ToBytesBigEndian(uint64(i+min))...) 427 require.Equal(fk[i], k) 428 v := hash.Hash256b(k) 429 require.Equal(fv[i], v[:]) 430 } 431 } 432 } 433 434 path := "test-filter.bolt" 435 testPath, err := testutil.PathOfTempFile(path) 436 require.NoError(err) 437 defer testutil.CleanupPath(testPath) 438 cfg := DefaultConfig 439 cfg.DbPath = testPath 440 441 t.Run("test filter", func(t *testing.T) { 442 testFunc(NewBoltDB(cfg), t) 443 }) 444 } 445 446 func TestCreateKVStore(t *testing.T) { 447 require := require.New(t) 448 449 path := "test-kv-db.bolt" 450 testPath, err := testutil.PathOfTempFile(path) 451 require.NoError(err) 452 defer testutil.CleanupPath(testPath) 453 cfg := DefaultConfig 454 455 d, err := CreateKVStore(cfg, testPath) 456 require.NoError(err) 457 require.NotNil(d) 458 459 d, err = CreateKVStore(cfg, "") 460 require.ErrorIs(err, ErrEmptyDBPath) 461 require.Nil(d) 462 463 d, err = CreateKVStoreWithCache(cfg, testPath, 5) 464 require.NoError(err) 465 require.NotNil(d) 466 }