295 lines
7.5 KiB
Go
295 lines
7.5 KiB
Go
package graviton
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"math/rand"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func randString(len int) string {
|
|
buff := make([]byte, len)
|
|
rand.Read(buff)
|
|
return base64.StdEncoding.EncodeToString(buff)
|
|
}
|
|
|
|
// this test various diffing related code
|
|
func TestDiffTree(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{}
|
|
|
|
var keys []string
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
|
for i := 0; i < 100000; i++ {
|
|
key := randString(32)
|
|
value := randString(8)
|
|
keyval_reference[key] = value
|
|
|
|
keys = append(keys, key)
|
|
tree.Put([]byte(key), []byte(value))
|
|
}
|
|
|
|
tree.Commit() // commit the tree
|
|
|
|
insert_map_reference := map[string]string{}
|
|
delete_map_reference := map[string]string{}
|
|
modify_map_reference := map[string]string{}
|
|
|
|
insert_map_actual := map[string]string{}
|
|
delete_map_actual := map[string]string{}
|
|
modify_map_actual := map[string]string{}
|
|
|
|
for i := 0; i < len(keyval_reference)/3; i++ {
|
|
key := randString(32)
|
|
value := randString(8)
|
|
_ = key
|
|
_ = value
|
|
insert_map_reference[key] = value
|
|
tree.Put([]byte(key), []byte(value))
|
|
}
|
|
|
|
for k := range keyval_reference {
|
|
if len(modify_map_reference) < len(keyval_reference)/3 {
|
|
value := randString(8)
|
|
modify_map_reference[k] = value
|
|
tree.Put([]byte(k), []byte(value))
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
|
|
// delete should be after modify
|
|
for len(delete_map_reference) < len(insert_map_reference) {
|
|
rkey := keys[rand.Intn(len(keys))]
|
|
if _, ok := modify_map_reference[rkey]; !ok {
|
|
delete_map_reference[rkey] = keyval_reference[rkey]
|
|
tree.Delete([]byte(rkey))
|
|
}
|
|
}
|
|
|
|
tree.Commit() // commit the tree
|
|
|
|
gv1, _ := store.LoadSnapshot(1)
|
|
base_tree, _ := gv1.GetTree("root")
|
|
|
|
gv2, _ := store.LoadSnapshot(2)
|
|
head_tree, _ := gv2.GetTree("root")
|
|
|
|
insert_handler := func(k, v []byte) {
|
|
insert_map_actual[string(k)] = string(v)
|
|
}
|
|
delete_handler := func(k, v []byte) {
|
|
delete_map_actual[string(k)] = string(v)
|
|
}
|
|
|
|
modify_handler := func(k, v []byte) {
|
|
//t.Logf("k %s v %s reference %s" , string(k), string(v) , modify_map_reference[string(k)])
|
|
modify_map_actual[string(k)] = string(v)
|
|
}
|
|
|
|
err = Diff(base_tree, head_tree, delete_handler, modify_handler, insert_handler)
|
|
|
|
//t.Logf("err %s",err)
|
|
|
|
//t.Logf("delete %d modify %d insert %d", len(delete_map_actual), len(modify_map_actual), len(insert_map_actual) )
|
|
|
|
if !reflect.DeepEqual(insert_map_reference, insert_map_actual) {
|
|
t.Logf(" insert map reference %d actual %d", len(insert_map_reference), len(insert_map_actual))
|
|
t.Fatalf("inserts could not be diffed")
|
|
}
|
|
|
|
if !reflect.DeepEqual(delete_map_reference, delete_map_actual) {
|
|
t.Logf(" delete map count %d", len(delete_map_actual))
|
|
t.Fatalf("delete could not be diffed")
|
|
}
|
|
|
|
if !reflect.DeepEqual(modify_map_reference, modify_map_actual) {
|
|
t.Logf(" modify_handler reference %d actual %d", len(modify_map_reference), len(modify_map_actual))
|
|
|
|
t.Logf("refer %+v", modify_map_reference)
|
|
t.Logf("refer %+v", modify_map_actual)
|
|
t.Fatalf("modify could not be diffed")
|
|
}
|
|
|
|
// now we must swap the trees
|
|
|
|
insert_map_actual = map[string]string{}
|
|
delete_map_actual = map[string]string{}
|
|
modify_map_actual = map[string]string{}
|
|
|
|
insert_map_reference, delete_map_reference = delete_map_reference, insert_map_reference
|
|
for k, _ := range modify_map_reference {
|
|
modify_map_reference[k] = keyval_reference[k]
|
|
}
|
|
|
|
base_tree, head_tree = head_tree, base_tree // swap the actual tree
|
|
|
|
err = Diff(base_tree, head_tree, delete_handler, modify_handler, insert_handler)
|
|
|
|
//t.Logf("err %s",err)
|
|
|
|
//t.Logf("delete %d modify %d insert %d", len(delete_map_actual), len(modify_map_actual), len(insert_map_actual) )
|
|
|
|
if !reflect.DeepEqual(insert_map_reference, insert_map_actual) {
|
|
t.Logf(" insert map reference %d actual %d", len(insert_map_reference), len(insert_map_actual))
|
|
t.Fatalf("inserts could not be diffed")
|
|
}
|
|
|
|
if !reflect.DeepEqual(delete_map_reference, delete_map_actual) {
|
|
t.Logf(" delete map count %d", len(delete_map_actual))
|
|
t.Fatalf("delete could not be diffed")
|
|
}
|
|
|
|
if !reflect.DeepEqual(modify_map_reference, modify_map_actual) {
|
|
t.Logf(" modify_handler map count %d ", len(modify_map_actual))
|
|
t.Fatalf("modify could not be diffed")
|
|
}
|
|
|
|
}
|
|
|
|
// this test various cursor diff related code
|
|
func TestDiffTree_Single_Key(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)
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
|
key := randString(32)
|
|
value := randString(8)
|
|
mod_value := randString(8)
|
|
|
|
tree.Put([]byte(key), []byte(value))
|
|
|
|
tree.Commit() // commit the tree
|
|
//tree.Hash()
|
|
|
|
//tree.graph("/tmp/1.dot")
|
|
|
|
tree.Put([]byte(key), []byte(mod_value))
|
|
tree.Commit() // commit the tree
|
|
// tree.graph("/tmp/2.dot")
|
|
|
|
gv1, _ := store.LoadSnapshot(1)
|
|
base_tree, _ := gv1.GetTree("root")
|
|
//base_tree.graph("/tmp/11.dot")
|
|
|
|
gv2, _ := store.LoadSnapshot(2)
|
|
head_tree, _ := gv2.GetTree("root")
|
|
// head_tree.graph("/tmp/12.dot")
|
|
|
|
insert_handler := func(k, v []byte) {
|
|
panic("insert")
|
|
}
|
|
delete_handler := func(k, v []byte) {
|
|
panic("insert")
|
|
}
|
|
|
|
mod_count := 0
|
|
|
|
modify_handler := func(k, v []byte) {
|
|
mod_count++
|
|
if mod_count > 1 {
|
|
panic("more modified")
|
|
}
|
|
if key != string(k) || mod_value != string(v) {
|
|
panic("modify failed")
|
|
}
|
|
}
|
|
|
|
err = Diff(base_tree, head_tree, delete_handler, modify_handler, insert_handler)
|
|
|
|
mod_count = 0
|
|
|
|
modify_handler = func(k, v []byte) {
|
|
|
|
//t.Logf("value %s mod_value %s v %s" , value, mod_value, string(v))
|
|
mod_count++
|
|
if mod_count > 1 {
|
|
panic("more modified")
|
|
}
|
|
if key != string(k) || value != string(v) {
|
|
panic("modify failed")
|
|
}
|
|
}
|
|
|
|
err = Diff(head_tree, base_tree, delete_handler, modify_handler, insert_handler)
|
|
|
|
}
|
|
|
|
// this test various diff related codes
|
|
// tree needs to be a particuar case, as some paths are hardcoded and manually triggered
|
|
func TestDiffTree_Single_Key_error_cases(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)
|
|
|
|
rand.Seed(1000)
|
|
|
|
key := randString(32)
|
|
value := randString(8)
|
|
|
|
tree.Put([]byte(key), []byte(value))
|
|
|
|
tree.Commit() // commit the tree
|
|
|
|
for i := 0; i < 8; i++ {
|
|
key1 := randStr(60)
|
|
value1 := randStr(512)
|
|
tree.Put([]byte(key1), []byte(value1))
|
|
}
|
|
tree.Commit() // commit the tree
|
|
|
|
gv1, _ := store.LoadSnapshot(1)
|
|
base_tree, _ := gv1.GetTree("root")
|
|
//base_tree.graph("/tmp/11.dot")
|
|
|
|
gv2, _ := store.LoadSnapshot(2)
|
|
head_tree, _ := gv2.GetTree("root")
|
|
// let corrupt head tree
|
|
|
|
head_tree.root.findex = 1000000000
|
|
head_tree.root.loaded_partial = true
|
|
|
|
dt := diffTree{base_tree: base_tree, head_tree: head_tree}
|
|
require.Error(t, dt.compare_nodes(base_tree.root, head_tree.root, nil, nil, nil))
|
|
|
|
base_tree, _ = gv1.GetTree("root")
|
|
base_tree.root.findex = 1000000000
|
|
base_tree.root.loaded_partial = true
|
|
require.Error(t, dt.compare_nodes(base_tree.root, head_tree.root, nil, nil, nil))
|
|
|
|
base_tree, _ = gv1.GetTree("root")
|
|
head_tree, _ = gv2.GetTree("root")
|
|
|
|
head_tree.root.left.(*inner).findex = 1000000000
|
|
head_tree.root.left.(*inner).loaded_partial = true
|
|
require.Error(t, dt.compare_nodes(nil, head_tree.root, nil, nil, nil))
|
|
|
|
// t.Logf("basehash %x", base_tree.Hash())
|
|
// t.Logf("headhash %x", head_tree.Hash())
|
|
|
|
require.Error(t, Diff(base_tree, head_tree, nil, nil, nil))
|
|
|
|
}
|