1
0
Fork 0
mirror of https://github.com/anyproto/any-sync.git synced 2025-06-08 05:57:03 +09:00
any-sync/commonspace/settings/settingsobject_test.go
2025-02-05 14:27:23 +01:00

258 lines
8.3 KiB
Go

package settings
import (
"context"
"sync"
"testing"
"time"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"github.com/anyproto/any-sync/accountservice/mock_accountservice"
"github.com/anyproto/any-sync/commonspace/deletionmanager/mock_deletionmanager"
"github.com/anyproto/any-sync/commonspace/headsync/headstorage"
"github.com/anyproto/any-sync/commonspace/headsync/headstorage/mock_headstorage"
"github.com/anyproto/any-sync/commonspace/headsync/statestorage"
"github.com/anyproto/any-sync/commonspace/headsync/statestorage/mock_statestorage"
"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/treemanager/mock_treemanager"
"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"
)
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_deletionmanager.MockDeletionManager
changeFactory *mock_settingsstate.MockChangeFactory
syncTree *mock_synctree.MockSyncTree
historyTree *mock_objecttree.MockObjectTree
account *mock_accountservice.MockService
stateStorage *mock_statestorage.MockStateStorage
headStorage *mock_headstorage.MockHeadStorage
}
var ctx = context.Background()
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)
delManager := mock_deletionmanager.NewMockDeletionManager(ctrl)
stateBuilder := mock_settingsstate.NewMockStateBuilder(ctrl)
changeFactory := mock_settingsstate.NewMockChangeFactory(ctrl)
syncTree := mock_synctree.NewMockSyncTree(ctrl)
historyTree := mock_objecttree.NewMockObjectTree(ctrl)
stateStorage := mock_statestorage.NewMockStateStorage(ctrl)
headStorage := mock_headstorage.NewMockHeadStorage(ctrl)
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,
DelManager: delManager,
changeFactory: changeFactory,
builder: stateBuilder,
}
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,
syncTree: syncTree,
account: acc,
historyTree: historyTree,
stateStorage: stateStorage,
headStorage: headStorage,
}
}
func (fx *settingsFixture) init(t *testing.T) {
fx.spaceStorage.EXPECT().StateStorage().AnyTimes().Return(fx.stateStorage)
fx.stateStorage.EXPECT().GetState(gomock.Any()).Return(statestorage.State{
SettingsId: fx.docId,
}, nil)
fx.spaceStorage.EXPECT().HeadStorage().AnyTimes().Return(fx.headStorage)
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.headStorage.EXPECT().GetEntry(gomock.Any(), gomock.Any()).Return(headstorage.HeadsEntry{
IsDerived: false,
}, 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(ctx, 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.headStorage.EXPECT().GetEntry(gomock.Any(), gomock.Any()).Return(headstorage.HeadsEntry{
IsDerived: false,
}, 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(ctx, delId)
require.NoError(t, err)
}
func TestSettingsObject_DeleteDerivedObject(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.headStorage.EXPECT().GetEntry(gomock.Any(), gomock.Any()).Return(headstorage.HeadsEntry{
IsDerived: true,
}, nil)
fx.doc.state = &settingsstate.State{LastIteratedId: "someId"}
err := fx.doc.DeleteObject(ctx, delId)
require.Equal(t, ErrCantDeleteDerivedObject, 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)
}