Merge pull request #65 from anytypeio/add-settings-snapshot
This commit is contained in:
commit
a4b3430d6e
@ -258,6 +258,20 @@ func (mr *MockObjectTreeMockRecorder) IterateRoot(arg0, arg1 interface{}) *gomoc
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateRoot", reflect.TypeOf((*MockObjectTree)(nil).IterateRoot), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateRoot", reflect.TypeOf((*MockObjectTree)(nil).IterateRoot), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Len mocks base method.
|
||||||
|
func (m *MockObjectTree) Len() int {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Len")
|
||||||
|
ret0, _ := ret[0].(int)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len indicates an expected call of Len.
|
||||||
|
func (mr *MockObjectTreeMockRecorder) Len() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Len", reflect.TypeOf((*MockObjectTree)(nil).Len))
|
||||||
|
}
|
||||||
|
|
||||||
// Lock mocks base method.
|
// Lock mocks base method.
|
||||||
func (m *MockObjectTree) Lock() {
|
func (m *MockObjectTree) Lock() {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|||||||
@ -57,6 +57,7 @@ type ReadableObjectTree interface {
|
|||||||
ChangeInfo() *treechangeproto.TreeChangeInfo
|
ChangeInfo() *treechangeproto.TreeChangeInfo
|
||||||
Heads() []string
|
Heads() []string
|
||||||
Root() *Change
|
Root() *Change
|
||||||
|
Len() int
|
||||||
|
|
||||||
AclList() list.AclList
|
AclList() list.AclList
|
||||||
|
|
||||||
@ -135,6 +136,10 @@ func (ot *objectTree) Id() string {
|
|||||||
return ot.id
|
return ot.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ot *objectTree) Len() int {
|
||||||
|
return ot.tree.Len()
|
||||||
|
}
|
||||||
|
|
||||||
func (ot *objectTree) AclList() list.AclList {
|
func (ot *objectTree) AclList() list.AclList {
|
||||||
return ot.aclList
|
return ot.aclList
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package objecttree
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/anytypeio/any-sync/util/crypto"
|
"github.com/anytypeio/any-sync/util/crypto"
|
||||||
|
"math/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
func commonSnapshotForTwoPaths(ourPath []string, theirPath []string) (string, error) {
|
func commonSnapshotForTwoPaths(ourPath []string, theirPath []string) (string, error) {
|
||||||
@ -40,3 +41,16 @@ func deriveTreeKey(key crypto.SymKey, cid string) (crypto.SymKey, error) {
|
|||||||
}
|
}
|
||||||
return crypto.DeriveSymmetricKey(raw, fmt.Sprintf(crypto.AnysyncTreePath, cid))
|
return crypto.DeriveSymmetricKey(raw, fmt.Sprintf(crypto.AnysyncTreePath, cid))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DoSnapshot(treeLen int) bool {
|
||||||
|
if treeLen <= 100 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
delta = treeLen/50 + 1
|
||||||
|
midPoint = 1000
|
||||||
|
val = rand.Intn(midPoint * 2)
|
||||||
|
)
|
||||||
|
return midPoint-delta <= val && val <= midPoint+delta
|
||||||
|
}
|
||||||
|
|||||||
@ -383,6 +383,20 @@ func (mr *MockSyncTreeMockRecorder) IterateRoot(arg0, arg1 interface{}) *gomock.
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateRoot", reflect.TypeOf((*MockSyncTree)(nil).IterateRoot), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateRoot", reflect.TypeOf((*MockSyncTree)(nil).IterateRoot), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Len mocks base method.
|
||||||
|
func (m *MockSyncTree) Len() int {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Len")
|
||||||
|
ret0, _ := ret[0].(int)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len indicates an expected call of Len.
|
||||||
|
func (mr *MockSyncTreeMockRecorder) Len() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Len", reflect.TypeOf((*MockSyncTree)(nil).Len))
|
||||||
|
}
|
||||||
|
|
||||||
// Lock mocks base method.
|
// Lock mocks base method.
|
||||||
func (m *MockSyncTree) Lock() {
|
func (m *MockSyncTree) Lock() {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|||||||
@ -40,6 +40,8 @@ var (
|
|||||||
ErrCantDeleteSpace = errors.New("not able to delete space")
|
ErrCantDeleteSpace = errors.New("not able to delete space")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var doSnapshot = objecttree.DoSnapshot
|
||||||
|
|
||||||
type BuildTreeFunc func(ctx context.Context, id string, listener updatelistener.UpdateListener) (t synctree.SyncTree, err error)
|
type BuildTreeFunc func(ctx context.Context, id string, listener updatelistener.UpdateListener) (t synctree.SyncTree, err error)
|
||||||
|
|
||||||
type Deps struct {
|
type Deps struct {
|
||||||
@ -228,14 +230,13 @@ func (s *settingsObject) DeleteObject(id string) (err error) {
|
|||||||
err = ErrObjDoesNotExist
|
err = ErrObjDoesNotExist
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
isSnapshot := doSnapshot(s.Len())
|
||||||
// TODO: add snapshot logic
|
res, err := s.changeFactory.CreateObjectDeleteChange(id, s.state, isSnapshot)
|
||||||
res, err := s.changeFactory.CreateObjectDeleteChange(id, s.state, false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.addContent(res)
|
return s.addContent(res, isSnapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *settingsObject) verifyDeleteSpace(raw *treechangeproto.RawTreeChangeWithId) (err error) {
|
func (s *settingsObject) verifyDeleteSpace(raw *treechangeproto.RawTreeChangeWithId) (err error) {
|
||||||
@ -246,12 +247,12 @@ func (s *settingsObject) verifyDeleteSpace(raw *treechangeproto.RawTreeChangeWit
|
|||||||
return verifyDeleteContent(data, "")
|
return verifyDeleteContent(data, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *settingsObject) addContent(data []byte) (err error) {
|
func (s *settingsObject) addContent(data []byte, isSnapshot bool) (err error) {
|
||||||
accountData := s.account.Account()
|
accountData := s.account.Account()
|
||||||
_, err = s.AddContent(context.Background(), objecttree.SignableChangeContent{
|
_, err = s.AddContent(context.Background(), objecttree.SignableChangeContent{
|
||||||
Data: data,
|
Data: data,
|
||||||
Key: accountData.SignKey,
|
Key: accountData.SignKey,
|
||||||
IsSnapshot: false,
|
IsSnapshot: isSnapshot,
|
||||||
IsEncrypted: false,
|
IsEncrypted: false,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -125,7 +125,7 @@ func TestSettingsObject_Init(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSettingsObject_DeleteObject(t *testing.T) {
|
func TestSettingsObject_DeleteObject_NoSnapshot(t *testing.T) {
|
||||||
fx := newSettingsFixture(t)
|
fx := newSettingsFixture(t)
|
||||||
defer fx.stop()
|
defer fx.stop()
|
||||||
|
|
||||||
@ -134,11 +134,14 @@ func TestSettingsObject_DeleteObject(t *testing.T) {
|
|||||||
|
|
||||||
err := fx.doc.Init(context.Background())
|
err := fx.doc.Init(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
|
|
||||||
delId := "delId"
|
delId := "delId"
|
||||||
|
doSnapshot = func(len int) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
fx.syncTree.EXPECT().Id().Return("syncId")
|
fx.syncTree.EXPECT().Id().Return("syncId")
|
||||||
|
fx.syncTree.EXPECT().Len().Return(10)
|
||||||
fx.delState.EXPECT().Exists(delId).Return(false)
|
fx.delState.EXPECT().Exists(delId).Return(false)
|
||||||
fx.spaceStorage.EXPECT().TreeStorage(delId).Return(nil, nil)
|
fx.spaceStorage.EXPECT().TreeStorage(delId).Return(nil, nil)
|
||||||
res := []byte("settingsData")
|
res := []byte("settingsData")
|
||||||
@ -165,6 +168,49 @@ func TestSettingsObject_DeleteObject(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSettingsObject_DeleteObject_WithSnapshot(t *testing.T) {
|
||||||
|
fx := newSettingsFixture(t)
|
||||||
|
defer fx.stop()
|
||||||
|
|
||||||
|
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
|
||||||
|
fx.deleter.EXPECT().Delete()
|
||||||
|
|
||||||
|
err := fx.doc.Init(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
delId := "delId"
|
||||||
|
doSnapshot = func(len int) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fx.syncTree.EXPECT().Id().Return("syncId")
|
||||||
|
fx.syncTree.EXPECT().Len().Return(10)
|
||||||
|
fx.delState.EXPECT().Exists(delId).Return(false)
|
||||||
|
fx.spaceStorage.EXPECT().TreeStorage(delId).Return(nil, nil)
|
||||||
|
res := []byte("settingsData")
|
||||||
|
fx.doc.state = &settingsstate.State{LastIteratedId: "someId"}
|
||||||
|
fx.changeFactory.EXPECT().CreateObjectDeleteChange(delId, fx.doc.state, true).Return(res, nil)
|
||||||
|
|
||||||
|
accountData, err := accountdata.NewRandom()
|
||||||
|
require.NoError(t, err)
|
||||||
|
fx.account.EXPECT().Account().Return(accountData)
|
||||||
|
fx.syncTree.EXPECT().AddContent(gomock.Any(), objecttree.SignableChangeContent{
|
||||||
|
Data: res,
|
||||||
|
Key: accountData.SignKey,
|
||||||
|
IsSnapshot: true,
|
||||||
|
IsEncrypted: false,
|
||||||
|
}).Return(objecttree.AddResult{}, nil)
|
||||||
|
|
||||||
|
fx.stateBuilder.EXPECT().Build(fx.doc, fx.doc.state).Return(fx.doc.state, nil)
|
||||||
|
fx.deletionManager.EXPECT().UpdateState(gomock.Any(), fx.doc.state).Return(nil)
|
||||||
|
err = fx.doc.DeleteObject(delId)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
fx.syncTree.EXPECT().Close().Return(nil)
|
||||||
|
err = fx.doc.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSettingsObject_Rebuild(t *testing.T) {
|
func TestSettingsObject_Rebuild(t *testing.T) {
|
||||||
fx := newSettingsFixture(t)
|
fx := newSettingsFixture(t)
|
||||||
defer fx.stop()
|
defer fx.stop()
|
||||||
|
|||||||
@ -24,9 +24,10 @@ func (c *changeFactory) CreateObjectDeleteChange(id string, state *State, isSnap
|
|||||||
Content: []*spacesyncproto.SpaceSettingsContent{
|
Content: []*spacesyncproto.SpaceSettingsContent{
|
||||||
{Value: content},
|
{Value: content},
|
||||||
},
|
},
|
||||||
Snapshot: nil,
|
|
||||||
}
|
}
|
||||||
// TODO: add snapshot logic
|
if isSnapshot {
|
||||||
|
change.Snapshot = c.makeSnapshot(state, id, "")
|
||||||
|
}
|
||||||
res, err = change.Marshal()
|
res, err = change.Marshal()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -39,9 +40,27 @@ func (c *changeFactory) CreateSpaceDeleteChange(peerId string, state *State, isS
|
|||||||
Content: []*spacesyncproto.SpaceSettingsContent{
|
Content: []*spacesyncproto.SpaceSettingsContent{
|
||||||
{Value: content},
|
{Value: content},
|
||||||
},
|
},
|
||||||
Snapshot: nil,
|
|
||||||
}
|
}
|
||||||
// TODO: add snapshot logic
|
if isSnapshot {
|
||||||
|
change.Snapshot = c.makeSnapshot(state, "", peerId)
|
||||||
|
}
|
||||||
res, err = change.Marshal()
|
res, err = change.Marshal()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *changeFactory) makeSnapshot(state *State, objectId, deleterPeer string) *spacesyncproto.SpaceSettingsSnapshot {
|
||||||
|
var (
|
||||||
|
deletedIds = state.DeletedIds
|
||||||
|
deleterId = state.DeleterId
|
||||||
|
)
|
||||||
|
if objectId != "" {
|
||||||
|
deletedIds = append(deletedIds, objectId)
|
||||||
|
}
|
||||||
|
if deleterPeer != "" {
|
||||||
|
deleterId = deleterPeer
|
||||||
|
}
|
||||||
|
return &spacesyncproto.SpaceSettingsSnapshot{
|
||||||
|
DeletedIds: deletedIds,
|
||||||
|
DeleterPeerId: deleterId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
59
commonspace/settings/settingsstate/changefactory_test.go
Normal file
59
commonspace/settings/settingsstate/changefactory_test.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package settingsstate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anytypeio/any-sync/commonspace/spacesyncproto"
|
||||||
|
"github.com/gogo/protobuf/proto"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestChangeFactory_CreateObjectDeleteChange(t *testing.T) {
|
||||||
|
factory := NewChangeFactory()
|
||||||
|
state := &State{
|
||||||
|
DeletedIds: []string{"1", "2"},
|
||||||
|
DeleterId: "del",
|
||||||
|
}
|
||||||
|
marshalled, err := factory.CreateObjectDeleteChange("3", state, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
data := &spacesyncproto.SettingsData{}
|
||||||
|
err = proto.Unmarshal(marshalled, data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, data.Snapshot)
|
||||||
|
require.Equal(t, "3", data.Content[0].Value.(*spacesyncproto.SpaceSettingsContent_ObjectDelete).ObjectDelete.Id)
|
||||||
|
|
||||||
|
marshalled, err = factory.CreateObjectDeleteChange("3", state, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
data = &spacesyncproto.SettingsData{}
|
||||||
|
err = proto.Unmarshal(marshalled, data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, &spacesyncproto.SpaceSettingsSnapshot{
|
||||||
|
DeletedIds: []string{"1", "2", "3"},
|
||||||
|
DeleterPeerId: "del",
|
||||||
|
}, data.Snapshot)
|
||||||
|
require.Equal(t, "3", data.Content[0].Value.(*spacesyncproto.SpaceSettingsContent_ObjectDelete).ObjectDelete.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChangeFactory_CreateSpaceDeleteChange(t *testing.T) {
|
||||||
|
factory := NewChangeFactory()
|
||||||
|
state := &State{
|
||||||
|
DeletedIds: []string{"1", "2"},
|
||||||
|
}
|
||||||
|
marshalled, err := factory.CreateSpaceDeleteChange("del", state, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
data := &spacesyncproto.SettingsData{}
|
||||||
|
err = proto.Unmarshal(marshalled, data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, data.Snapshot)
|
||||||
|
require.Equal(t, "del", data.Content[0].Value.(*spacesyncproto.SpaceSettingsContent_SpaceDelete).SpaceDelete.DeleterPeerId)
|
||||||
|
|
||||||
|
marshalled, err = factory.CreateSpaceDeleteChange("del", state, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
data = &spacesyncproto.SettingsData{}
|
||||||
|
err = proto.Unmarshal(marshalled, data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, &spacesyncproto.SpaceSettingsSnapshot{
|
||||||
|
DeletedIds: []string{"1", "2"},
|
||||||
|
DeleterPeerId: "del",
|
||||||
|
}, data.Snapshot)
|
||||||
|
require.Equal(t, "del", data.Content[0].Value.(*spacesyncproto.SpaceSettingsContent_SpaceDelete).SpaceDelete.DeleterPeerId)
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user