mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-08 05:57:03 +09:00
297 lines
9.1 KiB
Go
297 lines
9.1 KiB
Go
package settings
|
|
|
|
import (
|
|
"context"
|
|
"github.com/anyproto/any-sync/accountservice/mock_accountservice"
|
|
"github.com/anyproto/any-sync/commonspace/object/accountdata"
|
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree/mock_objecttree"
|
|
"github.com/anyproto/any-sync/commonspace/object/tree/synctree"
|
|
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/mock_synctree"
|
|
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/updatelistener"
|
|
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
|
"github.com/anyproto/any-sync/commonspace/object/treemanager/mock_treemanager"
|
|
"github.com/anyproto/any-sync/commonspace/settings/mock_settings"
|
|
"github.com/anyproto/any-sync/commonspace/settings/settingsstate"
|
|
"github.com/anyproto/any-sync/commonspace/settings/settingsstate/mock_settingsstate"
|
|
"github.com/anyproto/any-sync/commonspace/spacestorage/mock_spacestorage"
|
|
"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 *settingsObject
|
|
ctrl *gomock.Controller
|
|
treeManager *mock_treemanager.MockTreeManager
|
|
spaceStorage *mock_spacestorage.MockSpaceStorage
|
|
stateBuilder *mock_settingsstate.MockStateBuilder
|
|
deletionManager *mock_settings.MockDeletionManager
|
|
changeFactory *mock_settingsstate.MockChangeFactory
|
|
deleter *mock_settings.MockDeleter
|
|
syncTree *mock_synctree.MockSyncTree
|
|
historyTree *mock_objecttree.MockObjectTree
|
|
delState *mock_settingsstate.MockObjectDeletionState
|
|
account *mock_accountservice.MockService
|
|
}
|
|
|
|
func newSettingsFixture(t *testing.T) *settingsFixture {
|
|
spaceId := "spaceId"
|
|
objectId := "objectId"
|
|
|
|
ctrl := gomock.NewController(t)
|
|
acc := mock_accountservice.NewMockService(ctrl)
|
|
treeManager := mock_treemanager.NewMockTreeManager(ctrl)
|
|
st := mock_spacestorage.NewMockSpaceStorage(ctrl)
|
|
delState := mock_settingsstate.NewMockObjectDeletionState(ctrl)
|
|
delManager := mock_settings.NewMockDeletionManager(ctrl)
|
|
stateBuilder := mock_settingsstate.NewMockStateBuilder(ctrl)
|
|
changeFactory := mock_settingsstate.NewMockChangeFactory(ctrl)
|
|
syncTree := mock_synctree.NewMockSyncTree(ctrl)
|
|
historyTree := mock_objecttree.NewMockObjectTree(ctrl)
|
|
del := mock_settings.NewMockDeleter(ctrl)
|
|
|
|
delState.EXPECT().AddObserver(gomock.Any())
|
|
|
|
buildFunc := BuildTreeFunc(func(ctx context.Context, id string, listener updatelistener.UpdateListener) (synctree.SyncTree, error) {
|
|
require.Equal(t, objectId, id)
|
|
return newTestObjMock(syncTree), nil
|
|
})
|
|
buildHistoryTree = func(objTree objecttree.ObjectTree) (objecttree.ReadableObjectTree, error) {
|
|
return historyTree, nil
|
|
}
|
|
|
|
deps := Deps{
|
|
BuildFunc: buildFunc,
|
|
Account: acc,
|
|
TreeManager: treeManager,
|
|
Store: st,
|
|
DeletionState: delState,
|
|
delManager: delManager,
|
|
changeFactory: changeFactory,
|
|
builder: stateBuilder,
|
|
del: del,
|
|
}
|
|
doc := NewSettingsObject(deps, spaceId).(*settingsObject)
|
|
return &settingsFixture{
|
|
spaceId: spaceId,
|
|
docId: objectId,
|
|
doc: doc,
|
|
ctrl: ctrl,
|
|
treeManager: treeManager,
|
|
spaceStorage: st,
|
|
stateBuilder: stateBuilder,
|
|
changeFactory: changeFactory,
|
|
deletionManager: delManager,
|
|
deleter: del,
|
|
syncTree: syncTree,
|
|
account: acc,
|
|
delState: delState,
|
|
historyTree: historyTree,
|
|
}
|
|
}
|
|
|
|
func (fx *settingsFixture) init(t *testing.T) {
|
|
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
|
|
fx.deleter.EXPECT().Delete()
|
|
fx.stateBuilder.EXPECT().Build(fx.historyTree, nil).Return(&settingsstate.State{}, nil)
|
|
fx.doc.state = &settingsstate.State{}
|
|
|
|
err := fx.doc.Init(context.Background())
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func (fx *settingsFixture) stop(t *testing.T) {
|
|
fx.syncTree.EXPECT().Close().Return(nil)
|
|
|
|
err := fx.doc.Close()
|
|
require.NoError(t, err)
|
|
fx.ctrl.Finish()
|
|
}
|
|
|
|
func TestSettingsObject_Init(t *testing.T) {
|
|
fx := newSettingsFixture(t)
|
|
defer fx.stop(t)
|
|
|
|
fx.init(t)
|
|
}
|
|
|
|
func TestSettingsObject_DeleteObject_NoSnapshot(t *testing.T) {
|
|
fx := newSettingsFixture(t)
|
|
defer fx.stop(t)
|
|
|
|
fx.init(t)
|
|
|
|
delId := "delId"
|
|
DoSnapshot = func(len int) bool {
|
|
return false
|
|
}
|
|
|
|
fx.syncTree.EXPECT().Id().Return("syncId")
|
|
fx.syncTree.EXPECT().Len().Return(10)
|
|
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, false).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: false,
|
|
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)
|
|
}
|
|
|
|
func TestSettingsObject_DeleteObject_WithSnapshot(t *testing.T) {
|
|
fx := newSettingsFixture(t)
|
|
defer fx.stop(t)
|
|
|
|
fx.init(t)
|
|
delId := "delId"
|
|
DoSnapshot = func(len int) bool {
|
|
return true
|
|
}
|
|
|
|
fx.syncTree.EXPECT().Id().Return("syncId")
|
|
fx.syncTree.EXPECT().Len().Return(10)
|
|
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{Mode: objecttree.Rebuild}, nil)
|
|
|
|
fx.stateBuilder.EXPECT().Build(fx.doc, nil).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)
|
|
}
|
|
|
|
func TestSettingsObject_Rebuild(t *testing.T) {
|
|
fx := newSettingsFixture(t)
|
|
defer fx.stop(t)
|
|
|
|
fx.init(t)
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
newSt := &settingsstate.State{}
|
|
fx.doc.state = &settingsstate.State{}
|
|
fx.stateBuilder.EXPECT().Build(fx.doc, nil).Return(newSt, nil)
|
|
fx.deletionManager.EXPECT().UpdateState(gomock.Any(), newSt).Return(nil)
|
|
|
|
fx.doc.Rebuild(fx.doc)
|
|
}
|
|
|
|
func TestSettingsObject_Update(t *testing.T) {
|
|
fx := newSettingsFixture(t)
|
|
defer fx.stop(t)
|
|
|
|
fx.init(t)
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
fx.doc.state = &settingsstate.State{}
|
|
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)
|
|
|
|
fx.doc.Update(fx.doc)
|
|
}
|
|
|
|
func TestSettingsObject_DeleteSpace(t *testing.T) {
|
|
fx := newSettingsFixture(t)
|
|
defer fx.stop(t)
|
|
|
|
fx.init(t)
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
deleterId := "delId"
|
|
rawCh := &treechangeproto.RawTreeChangeWithId{
|
|
RawChange: []byte{1},
|
|
Id: "id",
|
|
}
|
|
changeFactory := settingsstate.NewChangeFactory()
|
|
delChange, _ := changeFactory.CreateSpaceDeleteChange(deleterId, &settingsstate.State{}, false)
|
|
|
|
fx.syncTree.EXPECT().UnpackChange(rawCh).Return(delChange, nil)
|
|
fx.syncTree.EXPECT().AddRawChanges(gomock.Any(), objecttree.RawChangesPayload{
|
|
NewHeads: []string{rawCh.Id},
|
|
RawChanges: []*treechangeproto.RawTreeChangeWithId{rawCh},
|
|
}).Return(objecttree.AddResult{
|
|
Heads: []string{rawCh.Id},
|
|
}, nil)
|
|
|
|
err := fx.doc.DeleteSpace(context.Background(), rawCh)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestSettingsObject_DeleteSpaceIncorrectChange(t *testing.T) {
|
|
fx := newSettingsFixture(t)
|
|
defer fx.stop(t)
|
|
|
|
fx.init(t)
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
t.Run("incorrect change type", func(t *testing.T) {
|
|
rawCh := &treechangeproto.RawTreeChangeWithId{
|
|
RawChange: []byte{1},
|
|
Id: "id",
|
|
}
|
|
changeFactory := settingsstate.NewChangeFactory()
|
|
delChange, _ := changeFactory.CreateObjectDeleteChange("otherId", &settingsstate.State{}, false)
|
|
|
|
fx.syncTree.EXPECT().UnpackChange(rawCh).Return(delChange, nil)
|
|
err := fx.doc.DeleteSpace(context.Background(), rawCh)
|
|
require.NotNil(t, err)
|
|
})
|
|
|
|
t.Run("empty peer", func(t *testing.T) {
|
|
rawCh := &treechangeproto.RawTreeChangeWithId{
|
|
RawChange: []byte{1},
|
|
Id: "id",
|
|
}
|
|
changeFactory := settingsstate.NewChangeFactory()
|
|
delChange, _ := changeFactory.CreateSpaceDeleteChange("", &settingsstate.State{}, false)
|
|
|
|
fx.syncTree.EXPECT().UnpackChange(rawCh).Return(delChange, nil)
|
|
err := fx.doc.DeleteSpace(context.Background(), rawCh)
|
|
require.NotNil(t, err)
|
|
})
|
|
}
|