package db0301 import ( "bytes" "os" "testing" "github.com/stretchr/testify/assert" ) func TestKVBasic(t *testing.T) { kv := KV{} kv.log.FileName = ".test_db" defer os.Remove(kv.log.FileName) os.Remove(kv.log.FileName) err := kv.Open() assert.Nil(t, err) defer kv.Close() updated, err := kv.Set([]byte("k1"), []byte("v1")) assert.True(t, updated && err == nil) val, ok, err := kv.Get([]byte("k1")) assert.True(t, string(val) == "v1" && ok && err == nil) _, ok, err = kv.Get([]byte("xxx")) assert.True(t, !ok && err == nil) updated, err = kv.Del([]byte("xxx")) assert.True(t, !updated && err == nil) updated, err = kv.Del([]byte("k1")) assert.True(t, updated && err == nil) _, ok, err = kv.Get([]byte("xxx")) assert.True(t, !ok && err == nil) updated, err = kv.Set([]byte("k2"), []byte("v2")) assert.True(t, updated && err == nil) // reopen kv.Close() err = kv.Open() assert.Nil(t, err) _, ok, err = kv.Get([]byte("k1")) assert.True(t, !ok && err == nil) val, ok, err = kv.Get([]byte("k2")) assert.True(t, string(val) == "v2" && ok && err == nil) } func TestKVUpdateMode(t *testing.T) { kv := KV{} kv.log.FileName = ".test_db" defer os.Remove(kv.log.FileName) os.Remove(kv.log.FileName) err := kv.Open() assert.Nil(t, err) defer kv.Close() updated, err := kv.SetEx([]byte("k1"), []byte("v1"), ModeUpdate) assert.True(t, !updated && err == nil) updated, err = kv.SetEx([]byte("k1"), []byte("v1"), ModeUpdate) assert.True(t, !updated && err == nil) updated, err = kv.SetEx([]byte("k1"), []byte("v1"), ModeInsert) assert.True(t, updated && err == nil) updated, err = kv.SetEx([]byte("k1"), []byte("xx"), ModeInsert) assert.True(t, !updated && err == nil) updated, err = kv.SetEx([]byte("k1"), []byte("yy"), ModeUpdate) assert.True(t, updated && err == nil) updated, err = kv.SetEx([]byte("k1"), []byte("zz"), ModeUpsert) assert.True(t, updated && err == nil) updated, err = kv.SetEx([]byte("k2"), []byte("tt"), ModeUpsert) assert.True(t, updated && err == nil) } func TestKVRecovery(t *testing.T) { kv := KV{} kv.log.FileName = ".test_db" defer os.Remove(kv.log.FileName) prepare := func() { os.Remove(kv.log.FileName) err := kv.Open() assert.Nil(t, err) defer kv.Close() updated, err := kv.Set([]byte("k1"), []byte("v1")) assert.True(t, updated && err == nil) updated, err = kv.Set([]byte("k2"), []byte("v2")) assert.True(t, updated && err == nil) } prepare() // simulate truncated log fp, _ := os.OpenFile(kv.log.FileName, os.O_RDWR, 0o644) st, _ := fp.Stat() fp.Truncate(st.Size() - 1) fp.Close() // reopen err := kv.Open() assert.Nil(t, err) // test val, ok, err := kv.Get([]byte("k1")) assert.True(t, string(val) == "v1" && ok && err == nil) _, ok, err = kv.Get([]byte("k2")) // bad assert.True(t, !ok && err == nil) kv.Close() prepare() // simulate bad checksum fp, _ = os.OpenFile(kv.log.FileName, os.O_RDWR, 0o644) st, _ = fp.Stat() fp.WriteAt([]byte{0}, st.Size()-1) fp.Close() // reopen err = kv.Open() assert.Nil(t, err) // test val, ok, err = kv.Get([]byte("k1")) assert.True(t, string(val) == "v1" && ok && err == nil) _, ok, err = kv.Get([]byte("k2")) // bad assert.True(t, !ok && err == nil) kv.Close() } func TestEntryEncode(t *testing.T) { ent := Entry{key: []byte("k1"), val: []byte("xxx")} data := []byte{0xe9, 0xec, 0x4d, 0x9e, 2, 0, 0, 0, 3, 0, 0, 0, 0, 'k', '1', 'x', 'x', 'x'} assert.Equal(t, data, ent.Encode()) decoded := Entry{} err := decoded.Decode(bytes.NewBuffer(data)) assert.Nil(t, err) assert.Equal(t, ent, decoded) ent = Entry{key: []byte("k1"), deleted: true} data = []byte{0x4c, 0xd0, 0xfe, 0xe5, 2, 0, 0, 0, 0, 0, 0, 0, 1, 'k', '1'} assert.Equal(t, data, ent.Encode()) decoded = Entry{} err = decoded.Decode(bytes.NewBuffer(data)) assert.Nil(t, err) assert.Equal(t, ent, decoded) } // QzBQWVJJOUhU https://trialofcode.org/