diff --git a/common/commonspace/diffservice/diffservice_test.go b/common/commonspace/diffservice/diffservice_test.go index ce3600c1..6cc21d90 100644 --- a/common/commonspace/diffservice/diffservice_test.go +++ b/common/commonspace/diffservice/diffservice_test.go @@ -3,7 +3,7 @@ package diffservice import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice/mock_diffservice" - "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate/mock_deletionstate" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage" mock_storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage/mock_storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff" @@ -24,7 +24,7 @@ func TestDiffService(t *testing.T) { treeStorageMock := mock_storage2.NewMockTreeStorage(ctrl) diffMock := mock_ldiff.NewMockDiff(ctrl) syncer := mock_diffservice.NewMockDiffSyncer(ctrl) - delState := deletionstate.NewDeletionState(storageMock) + delState := mock_deletionstate.NewMockDeletionState(ctrl) syncPeriod := 1 initId := "initId" diff --git a/common/commonspace/diffservice/diffsyncer_test.go b/common/commonspace/diffservice/diffsyncer_test.go index fd74b232..88238b9a 100644 --- a/common/commonspace/diffservice/diffsyncer_test.go +++ b/common/commonspace/diffservice/diffsyncer_test.go @@ -5,10 +5,9 @@ import ( "fmt" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff" - "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate/mock_deletionstate" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto/mock_spacesyncproto" - "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter/mock_treegetter" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer" @@ -107,27 +106,22 @@ func TestDiffSyncer_Sync(t *testing.T) { factory := spacesyncproto.ClientFactoryFunc(func(cc drpc.Conn) spacesyncproto.DRPCSpaceClient { return clientMock }) - delState := deletionstate.NewDeletionState(stMock) + delState := mock_deletionstate.NewMockDeletionState(ctrl) spaceId := "spaceId" aclRootId := "aclRootId" l := logger.NewNamed(spaceId) diffSyncer := newDiffSyncer(spaceId, diffMock, connectorMock, cacheMock, stMock, factory, l) + delState.EXPECT().AddObserver(gomock.Any()) diffSyncer.Init(delState) - delStateAdd := func(deletedId string) { - stMock.EXPECT().TreeDeletedStatus(deletedId).Return("", nil) - stMock.EXPECT().SetTreeDeletedStatus(deletedId, storage.TreeDeletedStatusQueued) - diffMock.EXPECT().RemoveId(deletedId) - require.NoError(t, delState.Add([]string{deletedId})) - } - - t.Run("diff syncer sync simple", func(t *testing.T) { + t.Run("diff syncer sync", func(t *testing.T) { connectorMock.EXPECT(). GetResponsiblePeers(gomock.Any(), spaceId). Return([]peer.Peer{mockPeer{}}, nil) diffMock.EXPECT(). Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))). Return([]string{"new"}, []string{"changed"}, nil, nil) + delState.EXPECT().FilterJoin(gomock.Any()).Return([]string{"new", "changed"}) for _, arg := range []string{"new", "changed"} { cacheMock.EXPECT(). GetTree(gomock.Any(), spaceId, arg). @@ -136,22 +130,6 @@ func TestDiffSyncer_Sync(t *testing.T) { require.NoError(t, diffSyncer.Sync(ctx)) }) - t.Run("diff syncer sync filtered", func(t *testing.T) { - delStateAdd("changed") - connectorMock.EXPECT(). - GetResponsiblePeers(gomock.Any(), spaceId). - Return([]peer.Peer{mockPeer{}}, nil) - diffMock.EXPECT(). - Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))). - Return([]string{"new1", "new2"}, []string{"changed"}, nil, nil) - for _, arg := range []string{"new1", "new2"} { - cacheMock.EXPECT(). - GetTree(gomock.Any(), spaceId, arg). - Return(nil, nil) - } - require.NoError(t, diffSyncer.Sync(ctx)) - }) - t.Run("diff syncer sync conf error", func(t *testing.T) { connectorMock.EXPECT(). GetResponsiblePeers(gomock.Any(), spaceId). @@ -162,7 +140,7 @@ func TestDiffSyncer_Sync(t *testing.T) { t.Run("deletion state remove objects", func(t *testing.T) { deletedId := "id" - delStateAdd(deletedId) + delState.EXPECT().Exists(deletedId).Return(true) // this should not result in any mock being called diffSyncer.UpdateHeads(deletedId, []string{"someHead"}) @@ -175,6 +153,7 @@ func TestDiffSyncer_Sync(t *testing.T) { Id: newId, Head: concatStrings(newHeads), }) + delState.EXPECT().Exists(newId).Return(false) diffSyncer.UpdateHeads(newId, newHeads) }) diff --git a/common/commonspace/diffservice/mock_diffservice/mock_diffservice.go b/common/commonspace/diffservice/mock_diffservice/mock_diffservice.go index f54342d9..1bca9970 100644 --- a/common/commonspace/diffservice/mock_diffservice/mock_diffservice.go +++ b/common/commonspace/diffservice/mock_diffservice/mock_diffservice.go @@ -36,7 +36,7 @@ func (m *MockDiffSyncer) EXPECT() *MockDiffSyncerMockRecorder { } // Init mocks base method. -func (m *MockDiffSyncer) Init(arg0 *deletionstate.DeletionState) { +func (m *MockDiffSyncer) Init(arg0 deletionstate.DeletionState) { m.ctrl.T.Helper() m.ctrl.Call(m, "Init", arg0) } diff --git a/common/commonspace/settingsdocument/deletionstate/deletionstate.go b/common/commonspace/settingsdocument/deletionstate/deletionstate.go index fe56f0b2..92f60cc3 100644 --- a/common/commonspace/settingsdocument/deletionstate/deletionstate.go +++ b/common/commonspace/settingsdocument/deletionstate/deletionstate.go @@ -1,6 +1,8 @@ +//go:generate mockgen -destination mock_deletionstate/mock_deletionstate.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate DeletionState package deletionstate import ( + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "sync" ) @@ -14,6 +16,7 @@ type DeletionState interface { Delete(id string) (err error) Exists(id string) bool FilterJoin(ids ...[]string) (filtered []string) + CreateDeleteChange(id string, isSnapshot bool) (res []byte, err error) } type deletionState struct { @@ -124,6 +127,21 @@ func (st *deletionState) FilterJoin(ids ...[]string) (filtered []string) { return } +func (st *deletionState) CreateDeleteChange(id string, isSnapshot bool) (res []byte, err error) { + content := &spacesyncproto.SpaceSettingsContent_ObjectDelete{ + ObjectDelete: &spacesyncproto.ObjectDelete{Id: id}, + } + change := &spacesyncproto.SettingsData{ + Content: []*spacesyncproto.SpaceSettingsContent{ + {content}, + }, + Snapshot: nil, + } + // TODO: add snapshot logic + res, err = change.Marshal() + return +} + func (st *deletionState) exists(id string) bool { if _, exists := st.deleted[id]; exists { return true diff --git a/common/commonspace/settingsdocument/deletionstate/mock_deletionstate/mock_deletionstate.go b/common/commonspace/settingsdocument/deletionstate/mock_deletionstate/mock_deletionstate.go new file mode 100644 index 00000000..12d2ce56 --- /dev/null +++ b/common/commonspace/settingsdocument/deletionstate/mock_deletionstate/mock_deletionstate.go @@ -0,0 +1,136 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate (interfaces: DeletionState) + +// Package mock_deletionstate is a generated GoMock package. +package mock_deletionstate + +import ( + reflect "reflect" + + deletionstate "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate" + gomock "github.com/golang/mock/gomock" +) + +// MockDeletionState is a mock of DeletionState interface. +type MockDeletionState struct { + ctrl *gomock.Controller + recorder *MockDeletionStateMockRecorder +} + +// MockDeletionStateMockRecorder is the mock recorder for MockDeletionState. +type MockDeletionStateMockRecorder struct { + mock *MockDeletionState +} + +// NewMockDeletionState creates a new mock instance. +func NewMockDeletionState(ctrl *gomock.Controller) *MockDeletionState { + mock := &MockDeletionState{ctrl: ctrl} + mock.recorder = &MockDeletionStateMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDeletionState) EXPECT() *MockDeletionStateMockRecorder { + return m.recorder +} + +// Add mocks base method. +func (m *MockDeletionState) Add(arg0 []string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Add", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Add indicates an expected call of Add. +func (mr *MockDeletionStateMockRecorder) Add(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Add", reflect.TypeOf((*MockDeletionState)(nil).Add), arg0) +} + +// AddObserver mocks base method. +func (m *MockDeletionState) AddObserver(arg0 deletionstate.StateUpdateObserver) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "AddObserver", arg0) +} + +// AddObserver indicates an expected call of AddObserver. +func (mr *MockDeletionStateMockRecorder) AddObserver(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddObserver", reflect.TypeOf((*MockDeletionState)(nil).AddObserver), arg0) +} + +// CreateDeleteChange mocks base method. +func (m *MockDeletionState) CreateDeleteChange(arg0 string, arg1 bool) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateDeleteChange", arg0, arg1) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateDeleteChange indicates an expected call of CreateDeleteChange. +func (mr *MockDeletionStateMockRecorder) CreateDeleteChange(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateDeleteChange", reflect.TypeOf((*MockDeletionState)(nil).CreateDeleteChange), arg0, arg1) +} + +// Delete mocks base method. +func (m *MockDeletionState) Delete(arg0 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockDeletionStateMockRecorder) Delete(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockDeletionState)(nil).Delete), arg0) +} + +// Exists mocks base method. +func (m *MockDeletionState) Exists(arg0 string) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Exists", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// Exists indicates an expected call of Exists. +func (mr *MockDeletionStateMockRecorder) Exists(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exists", reflect.TypeOf((*MockDeletionState)(nil).Exists), arg0) +} + +// FilterJoin mocks base method. +func (m *MockDeletionState) FilterJoin(arg0 ...[]string) []string { + m.ctrl.T.Helper() + varargs := []interface{}{} + for _, a := range arg0 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "FilterJoin", varargs...) + ret0, _ := ret[0].([]string) + return ret0 +} + +// FilterJoin indicates an expected call of FilterJoin. +func (mr *MockDeletionStateMockRecorder) FilterJoin(arg0 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FilterJoin", reflect.TypeOf((*MockDeletionState)(nil).FilterJoin), arg0...) +} + +// GetQueued mocks base method. +func (m *MockDeletionState) GetQueued() []string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetQueued") + ret0, _ := ret[0].([]string) + return ret0 +} + +// GetQueued indicates an expected call of GetQueued. +func (mr *MockDeletionStateMockRecorder) GetQueued() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueued", reflect.TypeOf((*MockDeletionState)(nil).GetQueued)) +} diff --git a/common/commonspace/settingsdocument/idprovider.go b/common/commonspace/settingsdocument/idprovider.go index 9ced17b3..6e42d0d2 100644 --- a/common/commonspace/settingsdocument/idprovider.go +++ b/common/commonspace/settingsdocument/idprovider.go @@ -21,33 +21,38 @@ func (p *provider) convert(decrypted []byte) (res any, err error) { return deleteChange, nil } +func (p *provider) processChange(change *tree.Change, tr tree.ObjectTree, startId string, ids []string) []string { + // ignoring root change which has empty model or startId change + if change.Model == nil || (change.Id == startId && startId != "") { + return ids + } + + deleteChange := change.Model.(*spacesyncproto.SettingsData) + // getting data from snapshot if we start from it + if change.Id == tr.Root().Id { + ids = deleteChange.Snapshot.DeletedIds + return ids + } + + // otherwise getting data from content + for _, cnt := range deleteChange.Content { + if cnt.GetObjectDelete() != nil { + ids = append(ids, cnt.GetObjectDelete().GetId()) + } + } + return ids +} + func (p *provider) ProvideIds(tr tree.ObjectTree, startId string) (ids []string, lastId string, err error) { - processChange := func(change *tree.Change) bool { - // ignoring root change which has empty model or startId change + process := func(change *tree.Change) bool { lastId = change.Id - if change.Model == nil || (change.Id == startId && startId != "") { - return true - } - - deleteChange := change.Model.(*spacesyncproto.SettingsData) - // getting data from snapshot if we start from it - if change.Id == tr.Root().Id { - ids = deleteChange.Snapshot.DeletedIds - return true - } - - // otherwise getting data from content - for _, cnt := range deleteChange.Content { - if cnt.GetObjectDelete() != nil { - ids = append(ids, cnt.GetObjectDelete().GetId()) - } - } + ids = p.processChange(change, tr, startId, ids) return true } if startId == "" { - err = tr.IterateFrom(tr.ID(), p.convert, processChange) + err = tr.IterateFrom(tr.ID(), p.convert, process) } else { - err = tr.IterateFrom(startId, p.convert, processChange) + err = tr.IterateFrom(startId, p.convert, process) } return } diff --git a/common/commonspace/settingsdocument/settingsdocument.go b/common/commonspace/settingsdocument/settingsdocument.go index 7bb034a6..fc05ad31 100644 --- a/common/commonspace/settingsdocument/settingsdocument.go +++ b/common/commonspace/settingsdocument/settingsdocument.go @@ -6,7 +6,6 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/account" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate" - "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener" @@ -78,6 +77,8 @@ func NewSettingsDocument(deps Deps, spaceId string) (doc SettingsDocument) { // this is needed mainly for testing if deps.prov == nil { s.prov = &provider{} + } else { + s.prov = deps.prov } doc = s @@ -113,6 +114,7 @@ func (s *settingsDocument) Init(ctx context.Context) (err error) { if err != nil { return } + s.loop.Run() return } @@ -129,29 +131,24 @@ func (s *settingsDocument) DeleteObject(id string) (err error) { return nil } - content := &spacesyncproto.SpaceSettingsContent_ObjectDelete{ - ObjectDelete: &spacesyncproto.ObjectDelete{Id: id}, - } - change := &spacesyncproto.SettingsData{ - Content: []*spacesyncproto.SpaceSettingsContent{ - {content}, - }, - Snapshot: nil, - } // TODO: add snapshot logic - res, err := change.Marshal() + res, err := s.deletionState.CreateDeleteChange(id, false) if err != nil { return } + + accountData := s.account.Account() _, err = s.AddContent(context.Background(), tree.SignableChangeContent{ Data: res, - Key: s.account.Account().SignKey, - Identity: s.account.Account().Identity, + Key: accountData.SignKey, + Identity: accountData.Identity, IsSnapshot: false, IsEncrypted: false, }) - if err == nil { - s.Update(s) + if err != nil { + return } + + s.Update(s) return } diff --git a/common/commonspace/settingsdocument/settingsdocument_test.go b/common/commonspace/settingsdocument/settingsdocument_test.go index 9ee5a9e4..d69e0fbc 100644 --- a/common/commonspace/settingsdocument/settingsdocument_test.go +++ b/common/commonspace/settingsdocument/settingsdocument_test.go @@ -3,30 +3,53 @@ package settingsdocument import ( "context" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/account/mock_account" - "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate/mock_deletionstate" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/mock_settingsdocument" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/mock_synctree" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter/mock_treegetter" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + "sync" "testing" "time" ) +type testSyncTreeMock struct { + *mock_synctree.MockSyncTree + m sync.Mutex +} + +func newTestObjMock(mockTree *mock_synctree.MockSyncTree) *testSyncTreeMock { + return &testSyncTreeMock{ + MockSyncTree: mockTree, + } +} + +func (t *testSyncTreeMock) Lock() { + t.m.Lock() +} + +func (t *testSyncTreeMock) Unlock() { + t.m.Unlock() +} + type settingsFixture struct { spaceId string docId string - doc SettingsDocument + doc *settingsDocument ctrl *gomock.Controller treeGetter *mock_treegetter.MockTreeGetter spaceStorage *mock_storage.MockSpaceStorage provider *mock_settingsdocument.MockDeletedIdsProvider deleter *mock_settingsdocument.MockDeleter syncTree *mock_synctree.MockSyncTree - delState *deletionstate.DeletionState + delState *mock_deletionstate.MockDeletionState account *mock_account.MockService } @@ -38,14 +61,16 @@ func newSettingsFixture(t *testing.T) *settingsFixture { acc := mock_account.NewMockService(ctrl) treeGetter := mock_treegetter.NewMockTreeGetter(ctrl) st := mock_storage.NewMockSpaceStorage(ctrl) - delState := deletionstate.NewDeletionState(st) + delState := mock_deletionstate.NewMockDeletionState(ctrl) prov := mock_settingsdocument.NewMockDeletedIdsProvider(ctrl) syncTree := mock_synctree.NewMockSyncTree(ctrl) del := mock_settingsdocument.NewMockDeleter(ctrl) + delState.EXPECT().AddObserver(gomock.Any()) + buildFunc := BuildTreeFunc(func(ctx context.Context, id string, listener updatelistener.UpdateListener) (synctree.SyncTree, error) { require.Equal(t, docId, id) - return syncTree, nil + return newTestObjMock(syncTree), nil }) deps := Deps{ @@ -57,7 +82,7 @@ func newSettingsFixture(t *testing.T) *settingsFixture { prov: prov, del: del, } - doc := NewSettingsDocument(deps, spaceId) + doc := NewSettingsDocument(deps, spaceId).(*settingsDocument) return &settingsFixture{ spaceId: spaceId, docId: docId, @@ -97,12 +122,67 @@ func TestSettingsDocument_DeleteObject(t *testing.T) { fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId) fx.deleter.EXPECT().Delete() - fx.syncTree.EXPECT().Close().Return(nil) err := fx.doc.Init(context.Background()) require.NoError(t, err) - time.Sleep(10 * time.Millisecond) + time.Sleep(100 * time.Millisecond) + delId := "delId" + + fx.delState.EXPECT().Exists(delId).Return(false) + res := []byte("settingsData") + fx.delState.EXPECT().CreateDeleteChange(delId, false).Return(res, nil) + + accountData := &account.AccountData{ + Identity: []byte("id"), + PeerKey: nil, + SignKey: &signingkey.Ed25519PrivateKey{}, + EncKey: nil, + } + fx.account.EXPECT().Account().Return(accountData) + fx.syncTree.EXPECT().AddContent(gomock.Any(), tree.SignableChangeContent{ + Data: res, + Key: accountData.SignKey, + Identity: accountData.Identity, + IsSnapshot: false, + IsEncrypted: false, + }).Return(tree.AddResult{}, nil) + + lastChangeId := "someId" + retIds := []string{"id1", "id2"} + fx.doc.lastChangeId = lastChangeId + fx.provider.EXPECT().ProvideIds(gomock.Not(nil), lastChangeId).Return(retIds, retIds[len(retIds)-1], nil) + fx.delState.EXPECT().Add(retIds).Return(nil) + err = fx.doc.DeleteObject(delId) + require.NoError(t, err) + require.Equal(t, retIds[len(retIds)-1], fx.doc.lastChangeId) + + fx.syncTree.EXPECT().Close().Return(nil) + err = fx.doc.Close() + require.NoError(t, err) +} + +func TestSettingsDocument_Rebuild(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) + time.Sleep(100 * time.Millisecond) + + lastChangeId := "someId" + retIds := []string{"id1", "id2"} + fx.doc.lastChangeId = lastChangeId + fx.provider.EXPECT().ProvideIds(gomock.Not(nil), "").Return(retIds, retIds[len(retIds)-1], nil) + fx.delState.EXPECT().Add(retIds).Return(nil) + + fx.doc.Rebuild(fx.doc) + require.Equal(t, retIds[len(retIds)-1], fx.doc.lastChangeId) + + fx.syncTree.EXPECT().Close().Return(nil) err = fx.doc.Close() require.NoError(t, err) }