package store import ( "bytes" "fmt" "os" "reflect" "testing" "github.com/siddontang/ledisdb/config" "github.com/siddontang/ledisdb/store/driver" ) func TestStore(t *testing.T) { cfg := config.NewConfigDefault() cfg.DataDir = "/tmp/testdb" cfg.LMDB.MapSize = 10 * 1024 * 1024 ns := driver.ListStores() for _, s := range ns { t.Logf("store %s", s) cfg.DBName = s os.RemoveAll(getStorePath(cfg)) db, err := Open(cfg) if err != nil { t.Fatal(err) } testStore(db, t) testClear(db, t) db.Close() } } func testStore(db *DB, t *testing.T) { testSimple(db, t) testBatch(db, t) testIterator(db, t) testSnapshot(db, t) testBatchData(db, t) } func testClear(db *DB, t *testing.T) { it := db.RangeIterator(nil, nil, RangeClose) for ; it.Valid(); it.Next() { db.Delete(it.RawKey()) } it.Close() } func testSimple(db *DB, t *testing.T) { key := []byte("key") value := []byte("hello world") if err := db.Put(key, value); err != nil { t.Fatal(err) } if v, err := db.Get(key); err != nil { t.Fatal(err) } else if !bytes.Equal(v, value) { t.Fatal("not equal") } if v, err := db.GetSlice(key); err != nil { t.Fatal(err) } else if v == nil { t.Fatal("must not nil") } else if !bytes.Equal(v.Data(), value) { t.Fatal("not equal") } else { v.Free() } if err := db.Delete(key); err != nil { t.Fatal(err) } if v, err := db.Get(key); err != nil { t.Fatal(err) } else if v != nil { t.Fatal("must nil") } if v, err := db.GetSlice(key); err != nil { t.Fatal(err) } else if v != nil { t.Fatal("must nil") } if err := db.Put(key, nil); err != nil { t.Fatal(err) } if v, err := db.Get(key); err != nil { t.Fatal(err) } else if !bytes.Equal(v, []byte{}) { t.Fatal("must empty") } } func testBatch(db *DB, t *testing.T) { key1 := []byte("key1") key2 := []byte("key2") value := []byte("hello world") db.Put(key1, value) db.Put(key2, value) wb := db.NewWriteBatch() wb.Delete(key2) wb.Put(key1, []byte("hello world2")) if err := wb.Commit(); err != nil { t.Fatal(err) } if v, err := db.Get(key2); err != nil { t.Fatal(err) } else if v != nil { t.Fatal("must nil") } if v, err := db.Get(key1); err != nil { t.Fatal(err) } else if string(v) != "hello world2" { t.Fatal(string(v)) } wb.Delete(key1) wb.Rollback() if v, err := db.Get(key1); err != nil { t.Fatal(err) } else if string(v) != "hello world2" { t.Fatal(string(v)) } wb.Put(key1, nil) wb.Put(key2, []byte{}) if err := wb.Commit(); err != nil { t.Fatal(err) } if v, err := db.Get(key1); err != nil { t.Fatal(err) } else if !bytes.Equal(v, []byte{}) { t.Fatal("must empty") } if v, err := db.Get(key2); err != nil { t.Fatal(err) } else if !bytes.Equal(v, []byte{}) { t.Fatal("must empty") } db.Delete(key1) db.Delete(key2) } func checkIterator(it *RangeLimitIterator, cv ...int) error { v := make([]string, 0, len(cv)) for ; it.Valid(); it.Next() { k := it.Key() if string(it.Value()) != "value" { return fmt.Errorf("invalid value") } v = append(v, string(k)) } it.Close() if len(v) != len(cv) { return fmt.Errorf("len error %d != %d", len(v), len(cv)) } for k, i := range cv { if fmt.Sprintf("key_%d", i) != v[k] { return fmt.Errorf("%s, %d", v[k], i) } } return nil } func testIterator(db *DB, t *testing.T) { i := db.NewIterator() for i.SeekToFirst(); i.Valid(); i.Next() { db.Delete(i.Key()) } i.Close() for i := 0; i < 10; i++ { key := []byte(fmt.Sprintf("key_%d", i)) value := []byte("value") db.Put(key, value) } i = db.NewIterator() i.SeekToFirst() if !i.Valid() { t.Fatal("must valid") } else if string(i.Key()) != "key_0" { t.Fatal(string(i.Key())) } i.Close() var it *RangeLimitIterator k := func(i int) []byte { return []byte(fmt.Sprintf("key_%d", i)) } it = db.RangeLimitIterator(k(1), k(5), RangeClose, 0, -1) if err := checkIterator(it, 1, 2, 3, 4, 5); err != nil { t.Fatal(err) } it.Close() it = db.RangeLimitIterator(k(1), k(5), RangeClose, 0, -1) if err := checkIterator(it, 1, 2, 3, 4, 5); err != nil { t.Fatal(err) } it.Close() it = db.RangeLimitIterator(k(1), k(5), RangeClose, 1, 3) if err := checkIterator(it, 2, 3, 4); err != nil { t.Fatal(err) } it.Close() it = db.RangeLimitIterator(k(1), k(5), RangeLOpen, 0, -1) if err := checkIterator(it, 2, 3, 4, 5); err != nil { t.Fatal(err) } it.Close() it = db.RangeLimitIterator(k(1), k(5), RangeROpen, 0, -1) if err := checkIterator(it, 1, 2, 3, 4); err != nil { t.Fatal(err) } it.Close() it = db.RangeLimitIterator(k(1), k(5), RangeOpen, 0, -1) if err := checkIterator(it, 2, 3, 4); err != nil { t.Fatal(err) } it.Close() it = db.RevRangeLimitIterator(k(1), k(5), RangeClose, 0, -1) if err := checkIterator(it, 5, 4, 3, 2, 1); err != nil { t.Fatal(err) } it.Close() it = db.RevRangeLimitIterator(k(1), k(5), RangeClose, 1, 3) if err := checkIterator(it, 4, 3, 2); err != nil { t.Fatal(err) } it.Close() it = db.RevRangeLimitIterator(k(1), k(5), RangeLOpen, 0, -1) if err := checkIterator(it, 5, 4, 3, 2); err != nil { t.Fatal(err) } it.Close() it = db.RevRangeLimitIterator(k(1), k(5), RangeROpen, 0, -1) if err := checkIterator(it, 4, 3, 2, 1); err != nil { t.Fatal(err) } it.Close() it = db.RevRangeLimitIterator(k(1), k(5), RangeOpen, 0, -1) if err := checkIterator(it, 4, 3, 2); err != nil { t.Fatal(err) } it.Close() } func testSnapshot(db *DB, t *testing.T) { foo := []byte("foo") bar := []byte("bar") v1 := []byte("v1") v2 := []byte("v2") db.Put(foo, v1) db.Put(bar, v1) snap, err := db.NewSnapshot() if err != nil { t.Fatal(err) } i := snap.NewIterator() i.Seek([]byte("foo")) if !i.Valid() { t.Fatal("must valid") } else if string(i.Value()) != "v1" { t.Fatal(string(i.Value())) } i.Close() db.Put(foo, v2) db.Put(bar, v2) if v, err := snap.Get(foo); err != nil { t.Fatal(err) } else if string(v) != "v1" { t.Fatal(string(v)) } if v, err := snap.Get(bar); err != nil { t.Fatal(err) } else if string(v) != "v1" { t.Fatal(string(v)) } if v, err := db.Get(foo); err != nil { t.Fatal(err) } else if string(v) != "v2" { t.Fatal(string(v)) } if v, err := db.Get(bar); err != nil { t.Fatal(err) } else if string(v) != "v2" { t.Fatal(string(v)) } snap.Close() if v, err := db.Get(foo); err != nil { t.Fatal(err) } else if string(v) != "v2" { t.Fatal(string(v)) } } func testBatchData(db *DB, t *testing.T) { w := db.NewWriteBatch() w.Put([]byte("a"), []byte("1")) w.Put([]byte("b"), nil) w.Delete([]byte("c")) d := w.BatchData() expected := []BatchItem{ {[]byte("a"), []byte("1")}, {[]byte("b"), []byte{}}, {[]byte("c"), nil}, } if kvs, err := d.Items(); err != nil { t.Fatal(err) } else if !reflect.DeepEqual(kvs, expected) { t.Fatalf("%v != %v", kvs, expected) } }