Adding the challenge 0404
This commit is contained in:
+212
@@ -0,0 +1,212 @@
|
||||
package db0404
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func TestKVSeek(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()
|
||||
|
||||
keys := []string{"c", "e", "g"}
|
||||
vals := []string{"3", "5", "7"}
|
||||
for i := range keys {
|
||||
_, _ = kv.Set([]byte(keys[i]), []byte(vals[i]))
|
||||
}
|
||||
|
||||
iter, err := kv.Seek([]byte("a"))
|
||||
require.Nil(t, err)
|
||||
for i := range keys {
|
||||
assert.True(t, iter.Valid())
|
||||
assert.Equal(t, []byte(keys[i]), iter.Key())
|
||||
assert.Equal(t, []byte(vals[i]), iter.Val())
|
||||
err = iter.Next()
|
||||
require.Nil(t, err)
|
||||
}
|
||||
assert.False(t, iter.Valid())
|
||||
|
||||
err = iter.Prev()
|
||||
require.Nil(t, err)
|
||||
for i := len(keys) - 1; i >= 0; i-- {
|
||||
assert.True(t, iter.Valid())
|
||||
assert.Equal(t, []byte(keys[i]), iter.Key())
|
||||
assert.Equal(t, []byte(vals[i]), iter.Val())
|
||||
err = iter.Prev()
|
||||
require.Nil(t, err)
|
||||
}
|
||||
assert.False(t, iter.Valid())
|
||||
|
||||
iter, err = kv.Seek([]byte("f"))
|
||||
require.Nil(t, err)
|
||||
assert.True(t, iter.Valid())
|
||||
assert.Equal(t, []byte("g"), iter.Key())
|
||||
|
||||
iter, err = kv.Seek([]byte("g"))
|
||||
require.Nil(t, err)
|
||||
assert.True(t, iter.Valid())
|
||||
assert.Equal(t, []byte("g"), iter.Key())
|
||||
|
||||
iter, err = kv.Seek([]byte("h"))
|
||||
require.Nil(t, err)
|
||||
assert.False(t, iter.Valid())
|
||||
}
|
||||
|
||||
// QzBQWVJJOUhU https://trialofcode.org/
|
||||
Reference in New Issue
Block a user