Improve validator logic and add tests

This commit is contained in:
mcrakhman 2023-04-13 23:55:28 +02:00 committed by Mikhail Iudin
parent 4a1a95a7b9
commit 977308edcc
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0
5 changed files with 207 additions and 141 deletions

View File

@ -2,83 +2,19 @@ package objecttree
import ( import (
"context" "context"
"crypto/rand"
"github.com/anytypeio/any-sync/commonspace/object/accountdata" "github.com/anytypeio/any-sync/commonspace/object/accountdata"
"github.com/anytypeio/any-sync/commonspace/object/acl/list" "github.com/anytypeio/any-sync/commonspace/object/acl/list"
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto" "github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage" "github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
"github.com/anytypeio/any-sync/util/crypto"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"testing" "testing"
) )
type mockKeyStorage struct {
key crypto.PubKey
}
func newKeyStorage() mockKeyStorage {
_, pk, _ := crypto.GenerateEd25519Key(rand.Reader)
return mockKeyStorage{pk}
}
func (m mockKeyStorage) PubKeyFromProto(protoBytes []byte) (crypto.PubKey, error) {
return m.key, nil
}
type mockChangeCreator struct{}
func (c *mockChangeCreator) createRoot(id, aclId string) *treechangeproto.RawTreeChangeWithId {
aclChange := &treechangeproto.RootChange{
AclHeadId: aclId,
}
res, _ := aclChange.Marshal()
raw := &treechangeproto.RawTreeChange{
Payload: res,
Signature: nil,
}
rawMarshalled, _ := raw.Marshal()
return &treechangeproto.RawTreeChangeWithId{
RawChange: rawMarshalled,
Id: id,
}
}
func (c *mockChangeCreator) createRaw(id, aclId, snapshotId string, isSnapshot bool, prevIds ...string) *treechangeproto.RawTreeChangeWithId {
aclChange := &treechangeproto.TreeChange{
TreeHeadIds: prevIds,
AclHeadId: aclId,
SnapshotBaseId: snapshotId,
ChangesData: nil,
IsSnapshot: isSnapshot,
}
res, _ := aclChange.Marshal()
raw := &treechangeproto.RawTreeChange{
Payload: res,
Signature: nil,
}
rawMarshalled, _ := raw.Marshal()
return &treechangeproto.RawTreeChangeWithId{
RawChange: rawMarshalled,
Id: id,
}
}
func (c *mockChangeCreator) createNewTreeStorage(treeId, aclHeadId string) treestorage.TreeStorage {
root := c.createRoot(treeId, aclHeadId)
treeStorage, _ := treestorage.NewInMemoryTreeStorage(root, []string{root.Id}, []*treechangeproto.RawTreeChangeWithId{root})
return treeStorage
}
type testTreeContext struct { type testTreeContext struct {
aclList list.AclList aclList list.AclList
treeStorage treestorage.TreeStorage treeStorage treestorage.TreeStorage
changeBuilder ChangeBuilder changeCreator *MockChangeCreator
changeCreator *mockChangeCreator
objTree ObjectTree objTree ObjectTree
} }
@ -91,12 +27,12 @@ func prepareAclList(t *testing.T) list.AclList {
return aclList return aclList
} }
func prepareTreeDeps(aclList list.AclList) (*mockChangeCreator, objectTreeDeps) { func prepareTreeDeps(aclList list.AclList) (*MockChangeCreator, objectTreeDeps) {
changeCreator := &mockChangeCreator{} changeCreator := NewMockChangeCreator()
treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id) treeStorage := changeCreator.CreateNewTreeStorage("0", aclList.Head().Id)
root, _ := treeStorage.Root() root, _ := treeStorage.Root()
changeBuilder := &nonVerifiableChangeBuilder{ changeBuilder := &nonVerifiableChangeBuilder{
ChangeBuilder: NewChangeBuilder(newKeyStorage(), root), ChangeBuilder: NewChangeBuilder(newMockKeyStorage(), root),
} }
deps := objectTreeDeps{ deps := objectTreeDeps{
changeBuilder: changeBuilder, changeBuilder: changeBuilder,
@ -110,23 +46,9 @@ func prepareTreeDeps(aclList list.AclList) (*mockChangeCreator, objectTreeDeps)
} }
func prepareTreeContext(t *testing.T, aclList list.AclList) testTreeContext { func prepareTreeContext(t *testing.T, aclList list.AclList) testTreeContext {
changeCreator := &mockChangeCreator{} changeCreator := NewMockChangeCreator()
treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id) treeStorage := changeCreator.CreateNewTreeStorage("0", aclList.Head().Id)
root, _ := treeStorage.Root() objTree, err := BuildTestableTree(aclList, treeStorage)
changeBuilder := &nonVerifiableChangeBuilder{
ChangeBuilder: NewChangeBuilder(newKeyStorage(), root),
}
deps := objectTreeDeps{
changeBuilder: changeBuilder,
treeBuilder: newTreeBuilder(treeStorage, changeBuilder),
treeStorage: treeStorage,
rawChangeLoader: newRawChangeLoader(treeStorage, changeBuilder),
validator: &noOpTreeValidator{},
aclList: aclList,
}
// check build
objTree, err := buildObjectTree(deps)
require.NoError(t, err, "building tree should be without error") require.NoError(t, err, "building tree should be without error")
// check tree iterate // check tree iterate
@ -140,7 +62,6 @@ func prepareTreeContext(t *testing.T, aclList list.AclList) testTreeContext {
return testTreeContext{ return testTreeContext{
aclList: aclList, aclList: aclList,
treeStorage: treeStorage, treeStorage: treeStorage,
changeBuilder: changeBuilder,
changeCreator: changeCreator, changeCreator: changeCreator,
objTree: objTree, objTree: objTree,
} }
@ -156,8 +77,8 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{ rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"), changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"), changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
} }
payload := RawChangesPayload{ payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id}, NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
@ -201,7 +122,7 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{ rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.createRaw("0", aclList.Head().Id, "", true, ""), changeCreator.CreateRaw("0", aclList.Head().Id, "", true, ""),
} }
payload := RawChangesPayload{ payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id}, NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
@ -225,7 +146,33 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{ rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"), changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
}
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
RawChanges: rawChanges,
}
res, err := objTree.AddRawChanges(context.Background(), payload)
require.NoError(t, err, "adding changes should be without error")
// check result
assert.Equal(t, []string{"0"}, res.OldHeads)
assert.Equal(t, []string{"0"}, res.Heads)
assert.Equal(t, 0, len(res.Added))
assert.Equal(t, Nothing, res.Mode)
// check tree heads
assert.Equal(t, []string{"0"}, objTree.Heads())
})
t.Run("add not connected changes", func(t *testing.T) {
ctx := prepareTreeContext(t, aclList)
changeCreator := ctx.changeCreator
objTree := ctx.objTree
// this change could in theory replace current snapshot, we should prevent that
rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.CreateRaw("2", aclList.Head().Id, "0", true, "1"),
} }
payload := RawChangesPayload{ payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id}, NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
@ -251,10 +198,10 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{ rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"), changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"), changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"), changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.createRaw("4", aclList.Head().Id, "3", false, "3"), changeCreator.CreateRaw("4", aclList.Head().Id, "3", false, "3"),
} }
payload := RawChangesPayload{ payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id}, NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
@ -301,9 +248,9 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{ rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"), changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"), changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"), changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
} }
payload := RawChangesPayload{ payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id}, NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
@ -325,12 +272,12 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{ rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"), changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"), changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"), changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.createRaw("4", aclList.Head().Id, "0", false, "2"), changeCreator.CreateRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.createRaw("5", aclList.Head().Id, "0", false, "1"), changeCreator.CreateRaw("5", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"), changeCreator.CreateRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"),
} }
payload := RawChangesPayload{ payload := RawChangesPayload{
@ -404,13 +351,13 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{ rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"), changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"), changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"), changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.createRaw("4", aclList.Head().Id, "0", false, "2"), changeCreator.CreateRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.createRaw("5", aclList.Head().Id, "0", false, "1"), changeCreator.CreateRaw("5", aclList.Head().Id, "0", false, "1"),
// main difference from tree example // main difference from tree example
changeCreator.createRaw("6", aclList.Head().Id, "0", true, "3", "4", "5"), changeCreator.CreateRaw("6", aclList.Head().Id, "0", true, "3", "4", "5"),
} }
payload := RawChangesPayload{ payload := RawChangesPayload{
@ -485,9 +432,9 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{ rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"), changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"), changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"), changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
} }
payload := RawChangesPayload{ payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id}, NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
@ -499,9 +446,9 @@ func TestObjectTree(t *testing.T) {
require.Equal(t, "3", objTree.Root().Id) require.Equal(t, "3", objTree.Root().Id)
rawChanges = []*treechangeproto.RawTreeChangeWithId{ rawChanges = []*treechangeproto.RawTreeChangeWithId{
changeCreator.createRaw("4", aclList.Head().Id, "0", false, "2"), changeCreator.CreateRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.createRaw("5", aclList.Head().Id, "0", false, "1"), changeCreator.CreateRaw("5", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"), changeCreator.CreateRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"),
} }
payload = RawChangesPayload{ payload = RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id}, NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
@ -545,12 +492,12 @@ func TestObjectTree(t *testing.T) {
changeCreator, deps := prepareTreeDeps(aclList) changeCreator, deps := prepareTreeDeps(aclList)
rawChanges := []*treechangeproto.RawTreeChangeWithId{ rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"), changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"), changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"), changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.createRaw("4", aclList.Head().Id, "0", false, "2"), changeCreator.CreateRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.createRaw("5", aclList.Head().Id, "0", false, "1"), changeCreator.CreateRaw("5", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"), changeCreator.CreateRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"),
} }
deps.treeStorage.TransactionAdd(rawChanges, []string{"6"}) deps.treeStorage.TransactionAdd(rawChanges, []string{"6"})
hTree, err := buildHistoryTree(deps, HistoryTreeParams{ hTree, err := buildHistoryTree(deps, HistoryTreeParams{
@ -576,12 +523,12 @@ func TestObjectTree(t *testing.T) {
changeCreator, deps := prepareTreeDeps(aclList) changeCreator, deps := prepareTreeDeps(aclList)
rawChanges := []*treechangeproto.RawTreeChangeWithId{ rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"), changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"), changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"), changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.createRaw("4", aclList.Head().Id, "0", false, "2"), changeCreator.CreateRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.createRaw("5", aclList.Head().Id, "0", false, "1"), changeCreator.CreateRaw("5", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"), changeCreator.CreateRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"),
} }
deps.treeStorage.TransactionAdd(rawChanges, []string{"6"}) deps.treeStorage.TransactionAdd(rawChanges, []string{"6"})
hTree, err := buildHistoryTree(deps, HistoryTreeParams{ hTree, err := buildHistoryTree(deps, HistoryTreeParams{
@ -623,4 +570,40 @@ func TestObjectTree(t *testing.T) {
assert.Equal(t, []string{"0"}, iterChangesId) assert.Equal(t, []string{"0"}, iterChangesId)
assert.Equal(t, "0", hTree.Root().Id) assert.Equal(t, "0", hTree.Root().Id)
}) })
t.Run("validate correct tree", func(t *testing.T) {
ctx := prepareTreeContext(t, aclList)
changeCreator := ctx.changeCreator
rawChanges := []*treechangeproto.RawTreeChangeWithId{
ctx.objTree.Header(),
changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
}
defaultObjectTreeDeps = nonVerifiableTreeDeps
err := ValidateRawTree(treestorage.TreeStorageCreatePayload{
RootRawChange: ctx.objTree.Header(),
Heads: []string{"3"},
Changes: rawChanges,
}, ctx.aclList)
require.NoError(t, err)
})
t.Run("fail to validate not connected tree", func(t *testing.T) {
ctx := prepareTreeContext(t, aclList)
changeCreator := ctx.changeCreator
rawChanges := []*treechangeproto.RawTreeChangeWithId{
ctx.objTree.Header(),
changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
}
defaultObjectTreeDeps = nonVerifiableTreeDeps
err := ValidateRawTree(treestorage.TreeStorageCreatePayload{
RootRawChange: ctx.objTree.Header(),
Heads: []string{"3"},
Changes: rawChanges,
}, ctx.aclList)
require.Equal(t, ErrHasInvalidChanges, err)
})
} }

View File

@ -33,7 +33,9 @@ type objectTreeDeps struct {
aclList list.AclList aclList list.AclList
} }
func defaultObjectTreeDeps( var defaultObjectTreeDeps = verifiableTreeDeps
func verifiableTreeDeps(
rootChange *treechangeproto.RawTreeChangeWithId, rootChange *treechangeproto.RawTreeChangeWithId,
treeStorage treestorage.TreeStorage, treeStorage treestorage.TreeStorage,
aclList list.AclList) objectTreeDeps { aclList list.AclList) objectTreeDeps {
@ -53,7 +55,7 @@ func nonVerifiableTreeDeps(
rootChange *treechangeproto.RawTreeChangeWithId, rootChange *treechangeproto.RawTreeChangeWithId,
treeStorage treestorage.TreeStorage, treeStorage treestorage.TreeStorage,
aclList list.AclList) objectTreeDeps { aclList list.AclList) objectTreeDeps {
changeBuilder := &nonVerifiableChangeBuilder{NewChangeBuilder(nil, rootChange)} changeBuilder := &nonVerifiableChangeBuilder{NewChangeBuilder(newMockKeyStorage(), rootChange)}
treeBuilder := newTreeBuilder(treeStorage, changeBuilder) treeBuilder := newTreeBuilder(treeStorage, changeBuilder)
return objectTreeDeps{ return objectTreeDeps{
changeBuilder: changeBuilder, changeBuilder: changeBuilder,

View File

@ -1,10 +1,12 @@
package objecttree package objecttree
import ( import (
"context"
"fmt" "fmt"
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto" "github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
"github.com/anytypeio/any-sync/commonspace/object/acl/list" "github.com/anytypeio/any-sync/commonspace/object/acl/list"
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage" "github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
"github.com/anytypeio/any-sync/util/slice"
) )
type ObjectTreeValidator interface { type ObjectTreeValidator interface {
@ -88,11 +90,23 @@ func (v *objectTreeValidator) validateChange(tree *Tree, aclList list.AclList, c
} }
func ValidateRawTree(payload treestorage.TreeStorageCreatePayload, aclList list.AclList) (err error) { func ValidateRawTree(payload treestorage.TreeStorageCreatePayload, aclList list.AclList) (err error) {
treeStorage, err := treestorage.NewInMemoryTreeStorage(payload.RootRawChange, payload.Heads, payload.Changes) treeStorage, err := treestorage.NewInMemoryTreeStorage(payload.RootRawChange, []string{payload.RootRawChange.Id}, nil)
if err != nil { if err != nil {
return return
} }
tree, err := BuildObjectTree(treeStorage, aclList)
_, err = BuildObjectTree(treeStorage, aclList) if err != nil {
return
}
res, err := tree.AddRawChanges(context.Background(), RawChangesPayload{
NewHeads: payload.Heads,
RawChanges: payload.Changes,
})
if err != nil {
return
}
if !slice.UnsortedEquals(res.Heads, payload.Heads) {
return ErrHasInvalidChanges
}
return return
} }

View File

@ -1,11 +1,66 @@
package objecttree package objecttree
import ( import (
"fmt"
"github.com/anytypeio/any-sync/commonspace/object/acl/list" "github.com/anytypeio/any-sync/commonspace/object/acl/list"
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto" "github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage" "github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
"github.com/anytypeio/any-sync/util/crypto"
libcrypto "github.com/libp2p/go-libp2p/core/crypto"
) )
type mockPubKey struct {
}
const mockKeyValue = "mockKey"
func (m mockPubKey) Equals(key crypto.Key) bool {
return true
}
func (m mockPubKey) Raw() ([]byte, error) {
return []byte(mockKeyValue), nil
}
func (m mockPubKey) Encrypt(message []byte) ([]byte, error) {
return message, nil
}
func (m mockPubKey) Verify(data []byte, sig []byte) (bool, error) {
return true, nil
}
func (m mockPubKey) Marshall() ([]byte, error) {
return []byte(mockKeyValue), nil
}
func (m mockPubKey) Storage() []byte {
return []byte(mockKeyValue)
}
func (m mockPubKey) Account() string {
return mockKeyValue
}
func (m mockPubKey) PeerId() string {
return mockKeyValue
}
func (m mockPubKey) LibP2P() (libcrypto.PubKey, error) {
return nil, fmt.Errorf("can't be converted in libp2p")
}
type mockKeyStorage struct {
}
func newMockKeyStorage() mockKeyStorage {
return mockKeyStorage{}
}
func (m mockKeyStorage) PubKeyFromProto(protoBytes []byte) (crypto.PubKey, error) {
return mockPubKey{}, nil
}
type MockChangeCreator struct{} type MockChangeCreator struct{}
func NewMockChangeCreator() *MockChangeCreator { func NewMockChangeCreator() *MockChangeCreator {
@ -61,7 +116,7 @@ func (c *MockChangeCreator) CreateNewTreeStorage(treeId, aclHeadId string) trees
func BuildTestableTree(aclList list.AclList, treeStorage treestorage.TreeStorage) (ObjectTree, error) { func BuildTestableTree(aclList list.AclList, treeStorage treestorage.TreeStorage) (ObjectTree, error) {
root, _ := treeStorage.Root() root, _ := treeStorage.Root()
changeBuilder := &nonVerifiableChangeBuilder{ changeBuilder := &nonVerifiableChangeBuilder{
ChangeBuilder: NewChangeBuilder(nil, root), ChangeBuilder: NewChangeBuilder(newMockKeyStorage(), root),
} }
deps := objectTreeDeps{ deps := objectTreeDeps{
changeBuilder: changeBuilder, changeBuilder: changeBuilder,

View File

@ -29,10 +29,11 @@ type processMsg struct {
} }
type msgDescription struct { type msgDescription struct {
name string name string
from string from string
to string to string
heads []string heads []string
changes []*treechangeproto.RawTreeChangeWithId
} }
func (p *processMsg) description() (descr msgDescription) { func (p *processMsg) description() (descr msgDescription) {
@ -50,14 +51,17 @@ func (p *processMsg) description() (descr msgDescription) {
cnt := unmarshalled.GetContent().GetHeadUpdate() cnt := unmarshalled.GetContent().GetHeadUpdate()
descr.name = "HeadUpdate" descr.name = "HeadUpdate"
descr.heads = cnt.Heads descr.heads = cnt.Heads
descr.changes = unmarshalled.GetContent().GetHeadUpdate().Changes
case unmarshalled.GetContent().GetFullSyncRequest() != nil: case unmarshalled.GetContent().GetFullSyncRequest() != nil:
cnt := unmarshalled.GetContent().GetFullSyncRequest() cnt := unmarshalled.GetContent().GetFullSyncRequest()
descr.name = "FullSyncRequest" descr.name = "FullSyncRequest"
descr.heads = cnt.Heads descr.heads = cnt.Heads
descr.changes = unmarshalled.GetContent().GetFullSyncRequest().Changes
case unmarshalled.GetContent().GetFullSyncResponse() != nil: case unmarshalled.GetContent().GetFullSyncResponse() != nil:
cnt := unmarshalled.GetContent().GetFullSyncResponse() cnt := unmarshalled.GetContent().GetFullSyncResponse()
descr.name = "FullSyncResponse" descr.name = "FullSyncResponse"
descr.heads = cnt.Heads descr.heads = cnt.Heads
descr.changes = unmarshalled.GetContent().GetFullSyncResponse().Changes
} }
return return
} }
@ -322,7 +326,7 @@ func (p *processFixture) stop() {
p.wg.Wait() p.wg.Wait()
} }
func TestSend_EmptyClient(t *testing.T) { func TestSend_EmptyClientGetsFullHistory(t *testing.T) {
treeId := "treeId" treeId := "treeId"
spaceId := "spaceId" spaceId := "spaceId"
keys, err := accountdata.NewRandom() keys, err := accountdata.NewRandom()
@ -345,7 +349,7 @@ func TestSend_EmptyClient(t *testing.T) {
fx.handlers["peer1"].sendRawChanges(context.Background(), objecttree.RawChangesPayload{ fx.handlers["peer1"].sendRawChanges(context.Background(), objecttree.RawChangesPayload{
NewHeads: nil, NewHeads: nil,
RawChanges: []*treechangeproto.RawTreeChangeWithId{ RawChanges: []*treechangeproto.RawTreeChangeWithId{
changeCreator.CreateRaw("1", aclList.Id(), treeId, false, treeId), changeCreator.CreateRaw("1", aclList.Id(), treeId, true, treeId),
}, },
}) })
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
@ -357,9 +361,17 @@ func TestSend_EmptyClient(t *testing.T) {
require.Equal(t, firstHeads, secondHeads) require.Equal(t, firstHeads, secondHeads)
require.Equal(t, []string{"1"}, firstHeads) require.Equal(t, []string{"1"}, firstHeads)
logMsgs := fx.log.batcher.GetAll() logMsgs := fx.log.batcher.GetAll()
var fullResponseMsg *processMsg
for _, msg := range logMsgs { for _, msg := range logMsgs {
fmt.Println(msg.description()) descr := msg.description()
if descr.name == "FullSyncResponse" {
fullResponseMsg = &msg
}
} }
require.NotNil(t, fullResponseMsg)
// that means that we got not only the last snapshot, but also the first one
require.Len(t, fullResponseMsg.description().changes, 2)
} }
func TestSimple_TwoPeers(t *testing.T) { func TestSimple_TwoPeers(t *testing.T) {