1
0
Fork 0
mirror of https://github.com/anyproto/any-sync.git synced 2025-06-10 18:10:54 +09:00

Update state builder to use map and fix tests

This commit is contained in:
mcrakhman 2023-05-23 10:49:28 +02:00 committed by Mikhail Iudin
parent c348ee2a49
commit da9bbba79b
No known key found for this signature in database
GPG key ID: FAAAA8BAABDFF1C0
11 changed files with 63 additions and 39 deletions

View file

@ -16,7 +16,7 @@ import (
"time" "time"
) )
func addIncorrectSnapshot(settingsObject settings.SettingsObject, acc *accountdata.AccountKeys, partialIds []string, newId string) (err error) { func addIncorrectSnapshot(settingsObject settings.SettingsObject, acc *accountdata.AccountKeys, partialIds map[string]struct{}, newId string) (err error) {
factory := settingsstate.NewChangeFactory() factory := settingsstate.NewChangeFactory()
bytes, err := factory.CreateObjectDeleteChange(newId, &settingsstate.State{DeletedIds: partialIds}, true) bytes, err := factory.CreateObjectDeleteChange(newId, &settingsstate.State{DeletedIds: partialIds}, true)
if err != nil { if err != nil {
@ -159,8 +159,12 @@ func TestSpaceDeleteIdsIncorrectSnapshot(t *testing.T) {
err = spc.DeleteTree(ctx, id) err = spc.DeleteTree(ctx, id)
require.NoError(t, err) require.NoError(t, err)
} }
mapIds := map[string]struct{}{}
for _, id := range ids[:partialObjs] {
mapIds[id] = struct{}{}
}
// adding snapshot that breaks the state // adding snapshot that breaks the state
err = addIncorrectSnapshot(settingsObject, acc, ids[:partialObjs], ids[partialObjs]) err = addIncorrectSnapshot(settingsObject, acc, mapIds, ids[partialObjs])
require.NoError(t, err) require.NoError(t, err)
// copying the contents of the settings tree // copying the contents of the settings tree
treesCopy[settingsObject.Id()] = settingsObject.Storage() treesCopy[settingsObject.Id()] = settingsObject.Storage()

View file

@ -4,7 +4,6 @@ import (
"context" "context"
"github.com/anytypeio/any-sync/commonspace/object/treemanager" "github.com/anytypeio/any-sync/commonspace/object/treemanager"
"github.com/anytypeio/any-sync/commonspace/settings/settingsstate" "github.com/anytypeio/any-sync/commonspace/settings/settingsstate"
"github.com/anytypeio/any-sync/util/slice"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -51,12 +50,16 @@ func (d *deletionManager) UpdateState(ctx context.Context, state *settingsstate.
if state.DeleterId == "" { if state.DeleterId == "" {
return nil return nil
} }
// we should delete space
log.Debug("deleting space") log.Debug("deleting space")
if d.isResponsible { if d.isResponsible {
allIds := slice.DiscardFromSlice(d.provider.AllIds(), func(id string) bool { mapIds := map[string]struct{}{}
return id == d.settingsId for _, id := range d.provider.AllIds() {
}) if id != d.settingsId {
d.deletionState.Add(allIds) mapIds[id] = struct{}{}
}
}
d.deletionState.Add(mapIds)
} }
d.onSpaceDelete() d.onSpaceDelete()
return nil return nil

View file

@ -19,7 +19,7 @@ func TestDeletionManager_UpdateState_NotResponsible(t *testing.T) {
spaceId := "spaceId" spaceId := "spaceId"
settingsId := "settingsId" settingsId := "settingsId"
state := &settingsstate.State{ state := &settingsstate.State{
DeletedIds: []string{"id"}, DeletedIds: map[string]struct{}{"id": {}},
DeleterId: "deleterId", DeleterId: "deleterId",
} }
deleted := false deleted := false
@ -51,7 +51,7 @@ func TestDeletionManager_UpdateState_Responsible(t *testing.T) {
spaceId := "spaceId" spaceId := "spaceId"
settingsId := "settingsId" settingsId := "settingsId"
state := &settingsstate.State{ state := &settingsstate.State{
DeletedIds: []string{"id"}, DeletedIds: map[string]struct{}{"id": struct{}{}},
DeleterId: "deleterId", DeleterId: "deleterId",
} }
deleted := false deleted := false
@ -64,7 +64,7 @@ func TestDeletionManager_UpdateState_Responsible(t *testing.T) {
delState.EXPECT().Add(state.DeletedIds) delState.EXPECT().Add(state.DeletedIds)
provider.EXPECT().AllIds().Return([]string{"id", "otherId", settingsId}) provider.EXPECT().AllIds().Return([]string{"id", "otherId", settingsId})
delState.EXPECT().Add([]string{"id", "otherId"}) delState.EXPECT().Add(map[string]struct{}{"id": {}, "otherId": {}})
delManager := newDeletionManager(spaceId, delManager := newDeletionManager(spaceId,
settingsId, settingsId,
true, true,

View file

@ -50,7 +50,7 @@ func (c *changeFactory) CreateSpaceDeleteChange(peerId string, state *State, isS
func (c *changeFactory) makeSnapshot(state *State, objectId, deleterPeer string) *spacesyncproto.SpaceSettingsSnapshot { func (c *changeFactory) makeSnapshot(state *State, objectId, deleterPeer string) *spacesyncproto.SpaceSettingsSnapshot {
var ( var (
deletedIds = state.DeletedIds deletedIds = make([]string, 0, len(state.DeletedIds)+1)
deleterId = state.DeleterId deleterId = state.DeleterId
) )
if objectId != "" { if objectId != "" {
@ -59,6 +59,9 @@ func (c *changeFactory) makeSnapshot(state *State, objectId, deleterPeer string)
if deleterPeer != "" { if deleterPeer != "" {
deleterId = deleterPeer deleterId = deleterPeer
} }
for id := range state.DeletedIds {
deletedIds = append(deletedIds, id)
}
return &spacesyncproto.SpaceSettingsSnapshot{ return &spacesyncproto.SpaceSettingsSnapshot{
DeletedIds: deletedIds, DeletedIds: deletedIds,
DeleterPeerId: deleterId, DeleterPeerId: deleterId,

View file

@ -4,13 +4,14 @@ import (
"github.com/anytypeio/any-sync/commonspace/spacesyncproto" "github.com/anytypeio/any-sync/commonspace/spacesyncproto"
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/exp/slices"
"testing" "testing"
) )
func TestChangeFactory_CreateObjectDeleteChange(t *testing.T) { func TestChangeFactory_CreateObjectDeleteChange(t *testing.T) {
factory := NewChangeFactory() factory := NewChangeFactory()
state := &State{ state := &State{
DeletedIds: []string{"1", "2"}, DeletedIds: map[string]struct{}{"1": {}, "2": {}},
DeleterId: "del", DeleterId: "del",
} }
marshalled, err := factory.CreateObjectDeleteChange("3", state, false) marshalled, err := factory.CreateObjectDeleteChange("3", state, false)
@ -26,6 +27,7 @@ func TestChangeFactory_CreateObjectDeleteChange(t *testing.T) {
data = &spacesyncproto.SettingsData{} data = &spacesyncproto.SettingsData{}
err = proto.Unmarshal(marshalled, data) err = proto.Unmarshal(marshalled, data)
require.NoError(t, err) require.NoError(t, err)
slices.Sort(data.Snapshot.DeletedIds)
require.Equal(t, &spacesyncproto.SpaceSettingsSnapshot{ require.Equal(t, &spacesyncproto.SpaceSettingsSnapshot{
DeletedIds: []string{"1", "2", "3"}, DeletedIds: []string{"1", "2", "3"},
DeleterPeerId: "del", DeleterPeerId: "del",
@ -36,7 +38,7 @@ func TestChangeFactory_CreateObjectDeleteChange(t *testing.T) {
func TestChangeFactory_CreateSpaceDeleteChange(t *testing.T) { func TestChangeFactory_CreateSpaceDeleteChange(t *testing.T) {
factory := NewChangeFactory() factory := NewChangeFactory()
state := &State{ state := &State{
DeletedIds: []string{"1", "2"}, DeletedIds: map[string]struct{}{"1": {}, "2": {}},
} }
marshalled, err := factory.CreateSpaceDeleteChange("del", state, false) marshalled, err := factory.CreateSpaceDeleteChange("del", state, false)
require.NoError(t, err) require.NoError(t, err)
@ -51,6 +53,7 @@ func TestChangeFactory_CreateSpaceDeleteChange(t *testing.T) {
data = &spacesyncproto.SettingsData{} data = &spacesyncproto.SettingsData{}
err = proto.Unmarshal(marshalled, data) err = proto.Unmarshal(marshalled, data)
require.NoError(t, err) require.NoError(t, err)
slices.Sort(data.Snapshot.DeletedIds)
require.Equal(t, &spacesyncproto.SpaceSettingsSnapshot{ require.Equal(t, &spacesyncproto.SpaceSettingsSnapshot{
DeletedIds: []string{"1", "2"}, DeletedIds: []string{"1", "2"},
DeleterPeerId: "del", DeleterPeerId: "del",

View file

@ -12,7 +12,7 @@ type StateUpdateObserver func(ids []string)
type ObjectDeletionState interface { type ObjectDeletionState interface {
AddObserver(observer StateUpdateObserver) AddObserver(observer StateUpdateObserver)
Add(ids []string) Add(ids map[string]struct{})
GetQueued() (ids []string) GetQueued() (ids []string)
Delete(id string) (err error) Delete(id string) (err error)
Exists(id string) bool Exists(id string) bool
@ -43,7 +43,7 @@ func (st *objectDeletionState) AddObserver(observer StateUpdateObserver) {
st.stateUpdateObservers = append(st.stateUpdateObservers, observer) st.stateUpdateObservers = append(st.stateUpdateObservers, observer)
} }
func (st *objectDeletionState) Add(ids []string) { func (st *objectDeletionState) Add(ids map[string]struct{}) {
var added []string var added []string
st.Lock() st.Lock()
defer func() { defer func() {
@ -53,7 +53,7 @@ func (st *objectDeletionState) Add(ids []string) {
} }
}() }()
for _, id := range ids { for id := range ids {
if _, exists := st.deleted[id]; exists { if _, exists := st.deleted[id]; exists {
continue continue
} }

View file

@ -38,7 +38,7 @@ func TestDeletionState_Add(t *testing.T) {
id := "newId" id := "newId"
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return("", nil) fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return("", nil)
fx.spaceStorage.EXPECT().SetTreeDeletedStatus(id, spacestorage.TreeDeletedStatusQueued).Return(nil) fx.spaceStorage.EXPECT().SetTreeDeletedStatus(id, spacestorage.TreeDeletedStatusQueued).Return(nil)
fx.delState.Add([]string{id}) fx.delState.Add(map[string]struct{}{id: {}})
require.Contains(t, fx.delState.queued, id) require.Contains(t, fx.delState.queued, id)
}) })
@ -47,7 +47,7 @@ func TestDeletionState_Add(t *testing.T) {
defer fx.stop() defer fx.stop()
id := "newId" id := "newId"
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return(spacestorage.TreeDeletedStatusQueued, nil) fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return(spacestorage.TreeDeletedStatusQueued, nil)
fx.delState.Add([]string{id}) fx.delState.Add(map[string]struct{}{id: {}})
require.Contains(t, fx.delState.queued, id) require.Contains(t, fx.delState.queued, id)
}) })
@ -56,7 +56,7 @@ func TestDeletionState_Add(t *testing.T) {
defer fx.stop() defer fx.stop()
id := "newId" id := "newId"
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return(spacestorage.TreeDeletedStatusDeleted, nil) fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return(spacestorage.TreeDeletedStatusDeleted, nil)
fx.delState.Add([]string{id}) fx.delState.Add(map[string]struct{}{id: {}})
require.Contains(t, fx.delState.deleted, id) require.Contains(t, fx.delState.deleted, id)
}) })
} }
@ -96,7 +96,7 @@ func TestDeletionState_AddObserver(t *testing.T) {
id := "newId" id := "newId"
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return("", nil) fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return("", nil)
fx.spaceStorage.EXPECT().SetTreeDeletedStatus(id, spacestorage.TreeDeletedStatusQueued).Return(nil) fx.spaceStorage.EXPECT().SetTreeDeletedStatus(id, spacestorage.TreeDeletedStatusQueued).Return(nil)
fx.delState.Add([]string{id}) fx.delState.Add(map[string]struct{}{id: {}})
require.Contains(t, fx.delState.queued, id) require.Contains(t, fx.delState.queued, id)
require.Equal(t, []string{id}, queued) require.Equal(t, []string{id}, queued)
} }

View file

@ -36,7 +36,7 @@ func (m *MockObjectDeletionState) EXPECT() *MockObjectDeletionStateMockRecorder
} }
// Add mocks base method. // Add mocks base method.
func (m *MockObjectDeletionState) Add(arg0 []string) { func (m *MockObjectDeletionState) Add(arg0 map[string]struct{}) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Add", arg0) m.ctrl.Call(m, "Add", arg0)
} }

View file

@ -1,15 +1,30 @@
package settingsstate package settingsstate
import "golang.org/x/exp/slices" import "github.com/anytypeio/any-sync/commonspace/spacesyncproto"
type State struct { type State struct {
DeletedIds []string DeletedIds map[string]struct{}
DeleterId string DeleterId string
LastIteratedId string LastIteratedId string
} }
func NewState() *State {
return &State{DeletedIds: map[string]struct{}{}}
}
func NewStateFromSnapshot(snapshot *spacesyncproto.SpaceSettingsSnapshot, lastIteratedId string) *State {
st := NewState()
for _, id := range snapshot.DeletedIds {
st.DeletedIds[id] = struct{}{}
}
st.DeleterId = snapshot.DeleterPeerId
st.LastIteratedId = lastIteratedId
return st
}
func (s *State) Exists(id string) bool { func (s *State) Exists(id string) bool {
// using map here will not give a lot of benefit, because this thing should be called only // using map here will not give a lot of benefit, because this thing should be called only
// when we are adding content, thus it doesn't matter // when we are adding content, thus it doesn't matter
return slices.Contains(s.DeletedIds, id) _, exists := s.DeletedIds[id]
return exists
} }

View file

@ -24,7 +24,7 @@ func (s *stateBuilder) Build(tr objecttree.ReadableObjectTree, oldState *State)
) )
state = oldState state = oldState
if state == nil { if state == nil {
state = &State{} state = NewState()
} else if state.LastIteratedId != "" { } else if state.LastIteratedId != "" {
startId = state.LastIteratedId startId = state.LastIteratedId
} }
@ -55,11 +55,7 @@ func (s *stateBuilder) processChange(change *objecttree.Change, rootId string, s
deleteChange := change.Model.(*spacesyncproto.SettingsData) deleteChange := change.Model.(*spacesyncproto.SettingsData)
// getting data from snapshot if we start from it // getting data from snapshot if we start from it
if change.Id == rootId { if change.Id == rootId {
state = &State{ state = NewStateFromSnapshot(deleteChange.Snapshot, rootId)
DeletedIds: deleteChange.Snapshot.DeletedIds,
DeleterId: deleteChange.Snapshot.DeleterPeerId,
LastIteratedId: rootId,
}
return state return state
} }
@ -67,7 +63,7 @@ func (s *stateBuilder) processChange(change *objecttree.Change, rootId string, s
for _, cnt := range deleteChange.Content { for _, cnt := range deleteChange.Content {
switch { switch {
case cnt.GetObjectDelete() != nil: case cnt.GetObjectDelete() != nil:
state.DeletedIds = append(state.DeletedIds, cnt.GetObjectDelete().GetId()) state.DeletedIds[cnt.GetObjectDelete().GetId()] = struct{}{}
case cnt.GetSpaceDelete() != nil: case cnt.GetSpaceDelete() != nil:
state.DeleterId = cnt.GetSpaceDelete().GetDeleterPeerId() state.DeleterId = cnt.GetSpaceDelete().GetDeleterPeerId()
} }

View file

@ -17,9 +17,9 @@ func TestStateBuilder_ProcessChange(t *testing.T) {
t.Run("empty model", func(t *testing.T) { t.Run("empty model", func(t *testing.T) {
ch := &objecttree.Change{} ch := &objecttree.Change{}
newSt := sb.processChange(ch, rootId, &State{ newSt := sb.processChange(ch, rootId, &State{
DeletedIds: []string{deletedId}, DeletedIds: map[string]struct{}{deletedId: struct{}{}},
}) })
require.Equal(t, []string{deletedId}, newSt.DeletedIds) require.Equal(t, map[string]struct{}{deletedId: struct{}{}}, newSt.DeletedIds)
}) })
t.Run("changeId is equal to startId, LastIteratedId is equal to startId", func(t *testing.T) { t.Run("changeId is equal to startId, LastIteratedId is equal to startId", func(t *testing.T) {
@ -34,10 +34,10 @@ func TestStateBuilder_ProcessChange(t *testing.T) {
ch.Id = "startId" ch.Id = "startId"
startId := "startId" startId := "startId"
newSt := sb.processChange(ch, rootId, &State{ newSt := sb.processChange(ch, rootId, &State{
DeletedIds: []string{deletedId}, DeletedIds: map[string]struct{}{deletedId: struct{}{}},
LastIteratedId: startId, LastIteratedId: startId,
}) })
require.Equal(t, []string{deletedId}, newSt.DeletedIds) require.Equal(t, map[string]struct{}{deletedId: struct{}{}}, newSt.DeletedIds)
}) })
t.Run("changeId is equal to rootId", func(t *testing.T) { t.Run("changeId is equal to rootId", func(t *testing.T) {
@ -50,8 +50,8 @@ func TestStateBuilder_ProcessChange(t *testing.T) {
}, },
} }
ch.Id = "rootId" ch.Id = "rootId"
newSt := sb.processChange(ch, rootId, &State{}) newSt := sb.processChange(ch, rootId, NewState())
require.Equal(t, []string{"id1", "id2"}, newSt.DeletedIds) require.Equal(t, map[string]struct{}{"id1": struct{}{}, "id2": struct{}{}}, newSt.DeletedIds)
require.Equal(t, "peerId", newSt.DeleterId) require.Equal(t, "peerId", newSt.DeleterId)
}) })
@ -66,8 +66,8 @@ func TestStateBuilder_ProcessChange(t *testing.T) {
}, },
} }
ch.Id = "someId" ch.Id = "someId"
newSt := sb.processChange(ch, rootId, &State{}) newSt := sb.processChange(ch, rootId, NewState())
require.Equal(t, []string{deletedId}, newSt.DeletedIds) require.Equal(t, map[string]struct{}{deletedId: struct{}{}}, newSt.DeletedIds)
}) })
} }