From 9c41f8d51fcda0c953758566cb476a938297d597 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Sun, 2 Oct 2022 22:40:13 +0200 Subject: [PATCH] Add head update tests --- common/commonspace/syncservice/synchandler.go | 3 + .../syncservice/synchandler_test.go | 200 +++++++++++++++--- 2 files changed, 177 insertions(+), 26 deletions(-) diff --git a/common/commonspace/syncservice/synchandler.go b/common/commonspace/syncservice/synchandler.go index d0edf03c..500e6e7b 100644 --- a/common/commonspace/syncservice/synchandler.go +++ b/common/commonspace/syncservice/synchandler.go @@ -62,6 +62,9 @@ func (s *syncHandler) handleHeadUpdate( // isEmptyUpdate is sent when the tree is brought up from cache if isEmptyUpdate { + if slice.UnsortedEquals(objTree.Heads(), update.Heads) { + return nil + } // we need to sync in any case fullRequest, err = s.syncClient.CreateFullSyncRequest(objTree, update.Heads, update.SnapshotPath, msg.TrackingId) return err diff --git a/common/commonspace/syncservice/synchandler_test.go b/common/commonspace/syncservice/synchandler_test.go index e8fa2b63..611dfeff 100644 --- a/common/commonspace/syncservice/synchandler_test.go +++ b/common/commonspace/syncservice/synchandler_test.go @@ -22,7 +22,7 @@ func (t treeContainer) Tree() tree.ObjectTree { return t.objTree } -func TestSyncHandler_HandleMessage(t *testing.T) { +func TestSyncHandler_HandleHeadUpdate(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -33,29 +33,177 @@ func TestSyncHandler_HandleMessage(t *testing.T) { objectTreeMock := mock_tree.NewMockObjectTree(ctrl) syncHandler := newSyncHandler(spaceId, cacheMock, syncClientMock) - treeId := "treeId" - senderId := "senderId" - chWithId := &treechangeproto.RawTreeChangeWithId{} - headUpdate := &spacesyncproto.ObjectHeadUpdate{ - Heads: []string{"h1"}, - Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, - SnapshotPath: []string{"h1"}, - } - msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "") - cacheMock.EXPECT(). - GetTree(gomock.Any(), spaceId, treeId). - Return(cache.TreeResult{ - Release: func() {}, - TreeContainer: treeContainer{objectTreeMock}, - }, nil) - objectTreeMock.EXPECT(). - Lock() - objectTreeMock.EXPECT(). - Heads().Return([]string{"h2"}) - objectTreeMock.EXPECT(). - AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})). - Return(tree.AddResult{}, nil) - objectTreeMock.EXPECT().Unlock() - err := syncHandler.HandleMessage(ctx, senderId, msg) - require.NoError(t, err) + t.Run("head update non empty all heads added", func(t *testing.T) { + treeId := "treeId" + senderId := "senderId" + chWithId := &treechangeproto.RawTreeChangeWithId{} + headUpdate := &spacesyncproto.ObjectHeadUpdate{ + Heads: []string{"h1"}, + Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, + SnapshotPath: []string{"h1"}, + } + msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "") + cacheMock.EXPECT(). + GetTree(gomock.Any(), spaceId, treeId). + Return(cache.TreeResult{ + Release: func() {}, + TreeContainer: treeContainer{objectTreeMock}, + }, nil) + objectTreeMock.EXPECT(). + Lock() + objectTreeMock.EXPECT(). + Heads(). + Return([]string{"h2"}) + objectTreeMock.EXPECT(). + HasChanges(gomock.Eq([]string{"h1"})). + Return(false) + objectTreeMock.EXPECT(). + AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})). + Return(tree.AddResult{}, nil) + objectTreeMock.EXPECT(). + Heads(). + Return([]string{"h2", "h1"}) + objectTreeMock.EXPECT(). + HasChanges(gomock.Eq([]string{"h1"})). + Return(true) + objectTreeMock.EXPECT(). + Unlock() + + err := syncHandler.HandleMessage(ctx, senderId, msg) + require.NoError(t, err) + }) + + t.Run("head update non empty heads not added", func(t *testing.T) { + treeId := "treeId" + senderId := "senderId" + chWithId := &treechangeproto.RawTreeChangeWithId{} + headUpdate := &spacesyncproto.ObjectHeadUpdate{ + Heads: []string{"h1"}, + Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, + SnapshotPath: []string{"h1"}, + } + fullRequest := &spacesyncproto.ObjectSyncMessage{} + msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "") + cacheMock.EXPECT(). + GetTree(gomock.Any(), spaceId, treeId). + Return(cache.TreeResult{ + Release: func() {}, + TreeContainer: treeContainer{objectTreeMock}, + }, nil) + objectTreeMock.EXPECT(). + Lock() + objectTreeMock.EXPECT(). + Heads(). + Return([]string{"h2"}) + objectTreeMock.EXPECT(). + HasChanges(gomock.Eq([]string{"h1"})). + Return(false) + objectTreeMock.EXPECT(). + AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})). + Return(tree.AddResult{}, nil) + objectTreeMock.EXPECT(). + Heads(). + Return([]string{"h2"}) + objectTreeMock.EXPECT(). + HasChanges(gomock.Eq([]string{"h1"})). + Return(false) + syncClientMock.EXPECT(). + CreateFullSyncRequest(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")). + Return(fullRequest, nil) + objectTreeMock.EXPECT(). + Unlock() + + syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest)) + err := syncHandler.HandleMessage(ctx, senderId, msg) + require.NoError(t, err) + }) + + t.Run("head update non empty equal heads", func(t *testing.T) { + treeId := "treeId" + senderId := "senderId" + chWithId := &treechangeproto.RawTreeChangeWithId{} + headUpdate := &spacesyncproto.ObjectHeadUpdate{ + Heads: []string{"h1"}, + Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, + SnapshotPath: []string{"h1"}, + } + msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "") + cacheMock.EXPECT(). + GetTree(gomock.Any(), spaceId, treeId). + Return(cache.TreeResult{ + Release: func() {}, + TreeContainer: treeContainer{objectTreeMock}, + }, nil) + objectTreeMock.EXPECT(). + Lock() + objectTreeMock.EXPECT(). + Heads(). + Return([]string{"h1"}) + objectTreeMock.EXPECT(). + Unlock() + + err := syncHandler.HandleMessage(ctx, senderId, msg) + require.NoError(t, err) + }) + + t.Run("head update empty", func(t *testing.T) { + treeId := "treeId" + senderId := "senderId" + chWithId := &treechangeproto.RawTreeChangeWithId{} + headUpdate := &spacesyncproto.ObjectHeadUpdate{ + Heads: []string{"h1"}, + Changes: nil, + SnapshotPath: []string{"h1"}, + } + fullRequest := &spacesyncproto.ObjectSyncMessage{} + msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "") + cacheMock.EXPECT(). + GetTree(gomock.Any(), spaceId, treeId). + Return(cache.TreeResult{ + Release: func() {}, + TreeContainer: treeContainer{objectTreeMock}, + }, nil) + objectTreeMock.EXPECT(). + Lock() + objectTreeMock.EXPECT(). + Heads(). + Return([]string{"h2"}) + syncClientMock.EXPECT(). + CreateFullSyncRequest(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")). + Return(fullRequest, nil) + objectTreeMock.EXPECT(). + Unlock() + + syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest)) + err := syncHandler.HandleMessage(ctx, senderId, msg) + require.NoError(t, err) + }) + + t.Run("head update empty equal heads", func(t *testing.T) { + treeId := "treeId" + senderId := "senderId" + chWithId := &treechangeproto.RawTreeChangeWithId{} + headUpdate := &spacesyncproto.ObjectHeadUpdate{ + Heads: []string{"h1"}, + Changes: nil, + SnapshotPath: []string{"h1"}, + } + msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "") + cacheMock.EXPECT(). + GetTree(gomock.Any(), spaceId, treeId). + Return(cache.TreeResult{ + Release: func() {}, + TreeContainer: treeContainer{objectTreeMock}, + }, nil) + objectTreeMock.EXPECT(). + Lock() + objectTreeMock.EXPECT(). + Heads(). + Return([]string{"h1"}) + objectTreeMock.EXPECT(). + Unlock() + + err := syncHandler.HandleMessage(ctx, senderId, msg) + require.NoError(t, err) + }) }