219 lines
5.1 KiB
Go
219 lines
5.1 KiB
Go
package graviton
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"fmt"
|
|
"math/rand"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func randStr(len int) string {
|
|
buff := make([]byte, len)
|
|
rand.Read(buff)
|
|
return base64.StdEncoding.EncodeToString(buff)
|
|
}
|
|
|
|
// this test various cursor related code
|
|
func TestCursor(t *testing.T) {
|
|
store, err := NewMemStore()
|
|
require.NoError(t, err)
|
|
gv, err := store.LoadSnapshot(0)
|
|
require.NoError(t, err)
|
|
|
|
tree, err := gv.GetTree("root")
|
|
require.NoError(t, err)
|
|
|
|
cursor := tree.Cursor()
|
|
|
|
first_key, first_value, err := cursor.First()
|
|
require.Error(t, err) // since tree is empty we must receive err
|
|
|
|
tree.Put([]byte("key"), []byte("value"))
|
|
first_key, first_value, err = cursor.First()
|
|
require.NoError(t, err) // since tree is not empty we must receive err
|
|
|
|
if string(first_key) != "key" || string(first_value) != "value" {
|
|
t.Fatalf("Cursor First failed")
|
|
}
|
|
|
|
}
|
|
|
|
// this test various cursor related code
|
|
func TestCursor1(t *testing.T) {
|
|
store, err := NewMemStore()
|
|
require.NoError(t, err)
|
|
gv, err := store.LoadSnapshot(0)
|
|
require.NoError(t, err)
|
|
|
|
tree, err := gv.GetTree("root")
|
|
require.NoError(t, err)
|
|
|
|
keyval_reference := map[string]string{}
|
|
|
|
for i := 0; i < 100000; i++ {
|
|
key := randStr(60)
|
|
value := randStr(512)
|
|
keyval_reference[key] = value
|
|
tree.Put([]byte(key), []byte(value))
|
|
}
|
|
|
|
test_committed_tree:
|
|
cursor := tree.Cursor()
|
|
|
|
key_copy := map[string]string{}
|
|
|
|
var key_array_left_to_right []string
|
|
var key_array_right_to_left []string
|
|
|
|
for k, v, err := cursor.First(); err == nil; k, v, err = cursor.Next() {
|
|
key_copy[string(k)] = string(v)
|
|
key_array_left_to_right = append(key_array_left_to_right, string(k))
|
|
|
|
//t.Logf("key %s val %s", string(k), string(v))
|
|
if _, ok := keyval_reference[string(k)]; !ok { // make sure spurious keys are not being generated
|
|
t.Fatalf(" missing key")
|
|
}
|
|
}
|
|
|
|
if len(keyval_reference) != len(key_copy) { // make sures elements are not duplicated
|
|
t.Fatalf(" missing key %d %d", len(keyval_reference), len(key_copy))
|
|
}
|
|
|
|
if tree.IsDirty() == false {
|
|
gv, err = store.LoadSnapshot(0)
|
|
require.NoError(t, err)
|
|
tree, _ = gv.GetTree("root")
|
|
cursor = tree.Cursor()
|
|
}
|
|
|
|
key_copy = map[string]string{}
|
|
for k, v, err := cursor.Last(); err == nil; k, v, err = cursor.Prev() {
|
|
key_copy[string(k)] = string(v)
|
|
key_array_right_to_left = append(key_array_right_to_left, string(k))
|
|
|
|
//t.Logf("key %s val %s", string(k), string(v))
|
|
if _, ok := keyval_reference[string(k)]; !ok {
|
|
t.Fatalf(" missing key")
|
|
}
|
|
}
|
|
|
|
if len(keyval_reference) != len(key_copy) {
|
|
t.Fatalf(" missing key %d %d", len(keyval_reference), len(key_copy))
|
|
}
|
|
|
|
for i := range key_array_right_to_left {
|
|
if key_array_left_to_right[i] != key_array_right_to_left[len(key_array_right_to_left)-i-1] {
|
|
t.Fatalf("Cursor corruption in reverse direction")
|
|
}
|
|
}
|
|
|
|
if tree.IsDirty() {
|
|
tree.Commit()
|
|
goto test_committed_tree
|
|
}
|
|
|
|
}
|
|
|
|
// this test various cursor related code
|
|
// this test uses hard coded values based on hash, chnaging the hash will cause this test to fails
|
|
// NOTE: this test is dependent on hash function
|
|
func TestCursor_error_case(t *testing.T) {
|
|
store, err := NewMemStore()
|
|
require.NoError(t, err)
|
|
gv, err := store.LoadSnapshot(0)
|
|
require.NoError(t, err)
|
|
|
|
tree, err := gv.GetTree("root")
|
|
require.NoError(t, err)
|
|
|
|
keys := map[string]string{}
|
|
for i := 0; i < 50000; i++ {
|
|
key := fmt.Sprintf("%d", i)
|
|
|
|
keyhash := sum([]byte(key))
|
|
|
|
keyhash_string := fmt.Sprintf("%02b", keyhash[0]>>6)
|
|
|
|
if _, ok := keys[keyhash_string]; !ok {
|
|
//t.Logf("%s key %s", keyhash_string, key)
|
|
|
|
keys[keyhash_string] = key
|
|
|
|
tree.Put([]byte(key), []byte(key))
|
|
|
|
if len(keys) == 4 {
|
|
break
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
tree.Commit()
|
|
|
|
//tree.graph("/tmp/graph.dot")
|
|
|
|
gv, err = store.LoadSnapshot(0)
|
|
require.NoError(t, err)
|
|
tree, _ = gv.GetTree("root")
|
|
cursor := tree.Cursor()
|
|
|
|
//corrupting root node error
|
|
tree.root.findex = 1000000000
|
|
tree.root.loaded_partial = true
|
|
_, _, err = cursor.First()
|
|
require.Error(t, err)
|
|
|
|
tree, _ = gv.GetTree("root")
|
|
cursor = tree.Cursor()
|
|
tree.root.left.(*inner).right.(*leaf).findex = 1000000000
|
|
tree.root.left.(*inner).right.(*leaf).loaded_partial = true
|
|
_, _, err = cursor.Next()
|
|
_, _, err = cursor.Next()
|
|
require.Error(t, err)
|
|
|
|
_, _, err = cursor.Last() // last leaf has been corrupted , so trigger this error
|
|
_, _, err = cursor.Prev()
|
|
_, _, err = cursor.Prev()
|
|
require.Error(t, err)
|
|
|
|
tree, _ = gv.GetTree("root")
|
|
cursor = tree.Cursor()
|
|
|
|
k, v, err := cursor.First()
|
|
tree.root.right.(*inner).findex = 1000000000
|
|
tree.root.right.(*inner).loaded_partial = true
|
|
|
|
//t.Logf("k \"%s\" v \"%s\" err \"%s\" %d ", string(k), string(v), err, len(cursor.node_path))
|
|
k, v, err = cursor.Next()
|
|
k, v, err = cursor.Next()
|
|
_ = k
|
|
_ = v
|
|
|
|
require.Error(t, err)
|
|
|
|
tree, _ = gv.GetTree("root")
|
|
cursor = tree.Cursor()
|
|
|
|
k, v, err = cursor.Last()
|
|
tree.root.left.(*inner).findex = 1000000000
|
|
tree.root.left.(*inner).loaded_partial = true
|
|
|
|
k, v, err = cursor.Prev()
|
|
k, v, err = cursor.Prev()
|
|
|
|
require.Error(t, err)
|
|
|
|
tree, err = gv.GetTree("damagedroot")
|
|
require.NoError(t, err)
|
|
|
|
tree.root.left = &dummynode{}
|
|
|
|
cursor = tree.Cursor()
|
|
|
|
k, v, err = cursor.next_internal(tree.root.left, false)
|
|
require.Error(t, err)
|
|
|
|
}
|