From 8e6237e885d0e80ef994e3868d3b6e5f2edd917e Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Thu, 29 Sep 2022 16:51:05 +0200 Subject: [PATCH 01/17] Separate diff service into components --- common/commonspace/diffservice/diffservice.go | 96 +++------------ common/commonspace/diffservice/diffsyncer.go | 112 ++++++++++++++++++ .../commonspace/diffservice/periodicsync.go | 39 +++--- common/commonspace/syncservice/syncservice.go | 4 +- 4 files changed, 153 insertions(+), 98 deletions(-) create mode 100644 common/commonspace/diffservice/diffsyncer.go diff --git a/common/commonspace/diffservice/diffservice.go b/common/commonspace/diffservice/diffservice.go index ff376d31..eab5c441 100644 --- a/common/commonspace/diffservice/diffservice.go +++ b/common/commonspace/diffservice/diffservice.go @@ -6,13 +6,10 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" - "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer" - "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff" "go.uber.org/zap" "strings" - "time" ) type DiffService interface { @@ -26,11 +23,9 @@ type DiffService interface { type diffService struct { spaceId string - periodicSync *periodicSync + periodicSync PeriodicSync storage storage.SpaceStorage - nconf nodeconf.Configuration diff ldiff.Diff - cache cache.TreeCache log *zap.Logger syncPeriod int @@ -40,23 +35,27 @@ func NewDiffService( spaceId string, syncPeriod int, storage storage.SpaceStorage, - nconf nodeconf.Configuration, + conf nodeconf.Configuration, cache cache.TreeCache, log *zap.Logger) DiffService { + diff := ldiff.New(16, 16) + l := log.With(zap.String("spaceId", spaceId)) + syncer := newDiffSyncer(spaceId, diff, conf, cache, storage, l) + periodicSync := newPeriodicSync(syncPeriod, syncer, l) + return &diffService{ - spaceId: spaceId, - storage: storage, - nconf: nconf, - cache: cache, - log: log, - syncPeriod: syncPeriod, + spaceId: spaceId, + storage: storage, + periodicSync: periodicSync, + diff: diff, + log: log, + syncPeriod: syncPeriod, } } func (d *diffService) Init(objectIds []string) { - d.periodicSync = newPeriodicSync(d.syncPeriod, d.sync, d.log.With(zap.String("spaceId", d.spaceId))) - d.diff = ldiff.New(16, 16) d.fillDiff(objectIds) + d.periodicSync.Run() } func (d *diffService) HandleRangeRequest(ctx context.Context, req *spacesyncproto.HeadSyncRequest) (resp *spacesyncproto.HeadSyncResponse, err error) { @@ -80,49 +79,6 @@ func (d *diffService) Close() (err error) { return nil } -func (d *diffService) sync(ctx context.Context) error { - st := time.Now() - // diffing with responsible peers according to configuration - peers, err := d.nconf.ResponsiblePeers(ctx, d.spaceId) - if err != nil { - return err - } - for _, p := range peers { - if err := d.syncWithPeer(ctx, p); err != nil { - d.log.Error("can't sync with peer", zap.String("peer", p.Id()), zap.Error(err)) - } - } - d.log.Info("synced", zap.String("spaceId", d.spaceId), zap.Duration("dur", time.Since(st))) - return nil -} - -func (d *diffService) syncWithPeer(ctx context.Context, p peer.Peer) (err error) { - cl := spacesyncproto.NewDRPCSpaceClient(p) - rdiff := remotediff.NewRemoteDiff(d.spaceId, cl) - newIds, changedIds, removedIds, err := d.diff.Diff(ctx, rdiff) - err = rpcerr.Unwrap(err) - if err != nil && err != spacesyncproto.ErrSpaceMissing { - return err - } - if err == spacesyncproto.ErrSpaceMissing { - return d.sendPushSpaceRequest(ctx, cl) - } - - d.pingTreesInCache(ctx, newIds) - d.pingTreesInCache(ctx, changedIds) - - d.log.Info("sync done:", zap.Int("newIds", len(newIds)), - zap.Int("changedIds", len(changedIds)), - zap.Int("removedIds", len(removedIds))) - return -} - -func (d *diffService) pingTreesInCache(ctx context.Context, trees []string) { - for _, tId := range trees { - _, _ = d.cache.GetTree(ctx, d.spaceId, tId) - } -} - func (d *diffService) fillDiff(objectIds []string) { var els = make([]ldiff.Element, 0, len(objectIds)) for _, id := range objectIds { @@ -142,30 +98,6 @@ func (d *diffService) fillDiff(objectIds []string) { d.diff.Set(els...) } -func (d *diffService) sendPushSpaceRequest(ctx context.Context, cl spacesyncproto.DRPCSpaceClient) (err error) { - aclStorage, err := d.storage.ACLStorage() - if err != nil { - return - } - - root, err := aclStorage.Root() - if err != nil { - return - } - - header, err := d.storage.SpaceHeader() - if err != nil { - return - } - - _, err = cl.PushSpace(ctx, &spacesyncproto.PushSpaceRequest{ - SpaceId: d.spaceId, - SpaceHeader: header, - AclRoot: root, - }) - return -} - func concatStrings(strs []string) string { var ( b strings.Builder diff --git a/common/commonspace/diffservice/diffsyncer.go b/common/commonspace/diffservice/diffsyncer.go new file mode 100644 index 00000000..8eec6c9b --- /dev/null +++ b/common/commonspace/diffservice/diffsyncer.go @@ -0,0 +1,112 @@ +package diffservice + +import ( + "context" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff" + "go.uber.org/zap" + "time" +) + +type DiffSyncer interface { + Sync(ctx context.Context) error +} + +func newDiffSyncer( + spaceId string, + diff ldiff.Diff, + nconf nodeconf.Configuration, + cache cache.TreeCache, + storage storage.SpaceStorage, + log *zap.Logger) DiffSyncer { + return &diffSyncer{ + diff: diff, + nconf: nconf, + spaceId: spaceId, + cache: cache, + storage: storage, + log: log, + } +} + +type diffSyncer struct { + diff ldiff.Diff + nconf nodeconf.Configuration + spaceId string + cache cache.TreeCache + storage storage.SpaceStorage + log *zap.Logger +} + +func (d *diffSyncer) Sync(ctx context.Context) error { + st := time.Now() + // diffing with responsible peers according to configuration + peers, err := d.nconf.ResponsiblePeers(ctx, d.spaceId) + if err != nil { + return err + } + for _, p := range peers { + if err := d.syncWithPeer(ctx, p); err != nil { + d.log.Error("can't sync with peer", zap.String("peer", p.Id()), zap.Error(err)) + } + } + d.log.Info("synced", zap.String("spaceId", d.spaceId), zap.Duration("dur", time.Since(st))) + return nil +} + +func (d *diffSyncer) syncWithPeer(ctx context.Context, p peer.Peer) (err error) { + cl := spacesyncproto.NewDRPCSpaceClient(p) + rdiff := remotediff.NewRemoteDiff(d.spaceId, cl) + newIds, changedIds, removedIds, err := d.diff.Diff(ctx, rdiff) + err = rpcerr.Unwrap(err) + if err != nil && err != spacesyncproto.ErrSpaceMissing { + return err + } + if err == spacesyncproto.ErrSpaceMissing { + return d.sendPushSpaceRequest(ctx, cl) + } + + d.pingTreesInCache(ctx, newIds) + d.pingTreesInCache(ctx, changedIds) + + d.log.Info("sync done:", zap.Int("newIds", len(newIds)), + zap.Int("changedIds", len(changedIds)), + zap.Int("removedIds", len(removedIds))) + return +} + +func (d *diffSyncer) pingTreesInCache(ctx context.Context, trees []string) { + for _, tId := range trees { + _, _ = d.cache.GetTree(ctx, d.spaceId, tId) + } +} + +func (d *diffSyncer) sendPushSpaceRequest(ctx context.Context, cl spacesyncproto.DRPCSpaceClient) (err error) { + aclStorage, err := d.storage.ACLStorage() + if err != nil { + return + } + + root, err := aclStorage.Root() + if err != nil { + return + } + + header, err := d.storage.SpaceHeader() + if err != nil { + return + } + + _, err = cl.PushSpace(ctx, &spacesyncproto.PushSpaceRequest{ + SpaceId: d.spaceId, + SpaceHeader: header, + AclRoot: root, + }) + return +} diff --git a/common/commonspace/diffservice/periodicsync.go b/common/commonspace/diffservice/periodicsync.go index 59616eab..a74b25cf 100644 --- a/common/commonspace/diffservice/periodicsync.go +++ b/common/commonspace/diffservice/periodicsync.go @@ -6,25 +6,34 @@ import ( "time" ) -func newPeriodicSync(periodSeconds int, sync func(ctx context.Context) error, l *zap.Logger) *periodicSync { +type PeriodicSync interface { + Run() + Close() +} + +func newPeriodicSync(periodSeconds int, syncer DiffSyncer, l *zap.Logger) *periodicSync { ctx, cancel := context.WithCancel(context.Background()) - ps := &periodicSync{ - log: l, - sync: sync, - syncCtx: ctx, - syncCancel: cancel, - syncLoopDone: make(chan struct{}), + return &periodicSync{ + syncer: syncer, + log: l, + syncCtx: ctx, + syncCancel: cancel, + syncLoopDone: make(chan struct{}), + periodSeconds: periodSeconds, } - go ps.syncLoop(periodSeconds) - return ps } type periodicSync struct { - log *zap.Logger - sync func(ctx context.Context) error - syncCtx context.Context - syncCancel context.CancelFunc - syncLoopDone chan struct{} + log *zap.Logger + syncer DiffSyncer + syncCtx context.Context + syncCancel context.CancelFunc + syncLoopDone chan struct{} + periodSeconds int +} + +func (p *periodicSync) Run() { + go p.syncLoop(p.periodSeconds) } func (p *periodicSync) syncLoop(periodSeconds int) { @@ -33,7 +42,7 @@ func (p *periodicSync) syncLoop(periodSeconds int) { doSync := func() { ctx, cancel := context.WithTimeout(p.syncCtx, time.Minute) defer cancel() - if err := p.sync(ctx); err != nil { + if err := p.syncer.Sync(ctx); err != nil { p.log.Warn("periodic sync error", zap.Error(err)) } } diff --git a/common/commonspace/syncservice/syncservice.go b/common/commonspace/syncservice/syncservice.go index 59aa3621..0d9bf722 100644 --- a/common/commonspace/syncservice/syncservice.go +++ b/common/commonspace/syncservice/syncservice.go @@ -103,6 +103,8 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) { cl := spacesyncproto.NewDRPCSpaceClient(peer) stream, err := cl.Stream(ctx) if err != nil { + err = rpcerr.Unwrap(err) + log.With("spaceId", s.spaceId).Errorf("failed to open stream: %v", err) // so here probably the request is failed because there is no such space, // but diffService should handle such cases by sending pushSpace continue @@ -111,7 +113,7 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) { err = stream.Send(&spacesyncproto.ObjectSyncMessage{SpaceId: s.spaceId}) if err != nil { err = rpcerr.Unwrap(err) - log.With("spaceId", s.spaceId).Errorf("failed to open stream: %v", err) + log.With("spaceId", s.spaceId).Errorf("failed to send first message to stream: %v", err) continue } s.streamPool.AddAndReadStreamAsync(stream) From 82eda9a0929f78fd69d9b8808f8b92f4222ad84a Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Fri, 30 Sep 2022 09:28:13 +0200 Subject: [PATCH 02/17] Prepare components for testing --- common/commonspace/diffservice/diffservice.go | 4 +- common/commonspace/diffservice/diffsyncer.go | 16 +- common/commonspace/payloads.go | 193 ++++++++++++++++++ common/commonspace/service.go | 182 +---------------- .../commonspace/spacesyncproto/spacesync.go | 15 +- common/commonspace/syncservice/syncservice.go | 14 +- 6 files changed, 234 insertions(+), 190 deletions(-) create mode 100644 common/commonspace/payloads.go diff --git a/common/commonspace/diffservice/diffservice.go b/common/commonspace/diffservice/diffservice.go index eab5c441..e5a94a1f 100644 --- a/common/commonspace/diffservice/diffservice.go +++ b/common/commonspace/diffservice/diffservice.go @@ -38,9 +38,11 @@ func NewDiffService( conf nodeconf.Configuration, cache cache.TreeCache, log *zap.Logger) DiffService { + diff := ldiff.New(16, 16) l := log.With(zap.String("spaceId", spaceId)) - syncer := newDiffSyncer(spaceId, diff, conf, cache, storage, l) + factory := spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient) + syncer := newDiffSyncer(spaceId, diff, conf, cache, storage, factory, l) periodicSync := newPeriodicSync(syncPeriod, syncer, l) return &diffService{ diff --git a/common/commonspace/diffservice/diffsyncer.go b/common/commonspace/diffservice/diffsyncer.go index 8eec6c9b..88cd00f4 100644 --- a/common/commonspace/diffservice/diffsyncer.go +++ b/common/commonspace/diffservice/diffsyncer.go @@ -24,6 +24,7 @@ func newDiffSyncer( nconf nodeconf.Configuration, cache cache.TreeCache, storage storage.SpaceStorage, + clientFactory spacesyncproto.ClientFactory, log *zap.Logger) DiffSyncer { return &diffSyncer{ diff: diff, @@ -36,12 +37,13 @@ func newDiffSyncer( } type diffSyncer struct { - diff ldiff.Diff - nconf nodeconf.Configuration - spaceId string - cache cache.TreeCache - storage storage.SpaceStorage - log *zap.Logger + spaceId string + diff ldiff.Diff + nconf nodeconf.Configuration + cache cache.TreeCache + storage storage.SpaceStorage + clientFactory spacesyncproto.ClientFactory + log *zap.Logger } func (d *diffSyncer) Sync(ctx context.Context) error { @@ -61,7 +63,7 @@ func (d *diffSyncer) Sync(ctx context.Context) error { } func (d *diffSyncer) syncWithPeer(ctx context.Context, p peer.Peer) (err error) { - cl := spacesyncproto.NewDRPCSpaceClient(p) + cl := d.clientFactory.Client(p) rdiff := remotediff.NewRemoteDiff(d.spaceId, cl) newIds, changedIds, removedIds, err := d.diff.Diff(ctx, rdiff) err = rpcerr.Unwrap(err) diff --git a/common/commonspace/payloads.go b/common/commonspace/payloads.go new file mode 100644 index 00000000..fae285ab --- /dev/null +++ b/common/commonspace/payloads.go @@ -0,0 +1,193 @@ +package commonspace + +import ( + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey" + "hash/fnv" + "math/rand" + "time" +) + +func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload storage.SpaceStorageCreatePayload, err error) { + // unmarshalling signing and encryption keys + identity, err := payload.SigningKey.GetPublic().Raw() + if err != nil { + return + } + encPubKey, err := payload.EncryptionKey.GetPublic().Raw() + if err != nil { + return + } + + // preparing header and space id + bytes := make([]byte, 32) + _, err = rand.Read(bytes) + if err != nil { + return + } + header := &spacesyncproto.SpaceHeader{ + Identity: identity, + Timestamp: time.Now().UnixNano(), + SpaceType: payload.SpaceType, + ReplicationKey: payload.ReplicationKey, + Seed: bytes, + } + marshalled, err := header.Marshal() + if err != nil { + return + } + id, err := cid.NewCIDFromBytes(marshalled) + if err != nil { + return + } + spaceId := NewSpaceId(id, payload.ReplicationKey) + + // encrypting read key + hasher := fnv.New64() + _, err = hasher.Write(payload.ReadKey) + if err != nil { + return + } + readKeyHash := hasher.Sum64() + encReadKey, err := payload.EncryptionKey.GetPublic().Encrypt(payload.ReadKey) + if err != nil { + return + } + + // preparing acl + aclRoot := &aclrecordproto.ACLRoot{ + Identity: identity, + EncryptionKey: encPubKey, + SpaceId: spaceId, + EncryptedReadKey: encReadKey, + DerivationScheme: "", + CurrentReadKeyHash: readKeyHash, + Timestamp: time.Now().UnixNano(), + } + rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey) + if err != nil { + return + } + + // creating storage + storagePayload = storage.SpaceStorageCreatePayload{ + RecWithId: rawWithId, + SpaceHeader: header, + Id: id, + } + return +} + +func storagePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload storage.SpaceStorageCreatePayload, err error) { + // unmarshalling signing and encryption keys + identity, err := payload.SigningKey.GetPublic().Raw() + if err != nil { + return + } + signPrivKey, err := payload.SigningKey.Raw() + if err != nil { + return + } + encPubKey, err := payload.EncryptionKey.GetPublic().Raw() + if err != nil { + return + } + encPrivKey, err := payload.EncryptionKey.Raw() + if err != nil { + return + } + + // preparing replication key + hasher := fnv.New64() + _, err = hasher.Write(identity) + if err != nil { + return + } + repKey := hasher.Sum64() + + // preparing header and space id + header := &spacesyncproto.SpaceHeader{ + Identity: identity, + SpaceType: SpaceTypeDerived, + ReplicationKey: repKey, + } + marshalled, err := header.Marshal() + if err != nil { + return + } + id, err := cid.NewCIDFromBytes(marshalled) + if err != nil { + return + } + spaceId := NewSpaceId(id, repKey) + + // deriving and encrypting read key + readKey, err := aclrecordproto.ACLReadKeyDerive(signPrivKey, encPrivKey) + if err != nil { + return + } + hasher = fnv.New64() + _, err = hasher.Write(readKey.Bytes()) + if err != nil { + return + } + readKeyHash := hasher.Sum64() + encReadKey, err := payload.EncryptionKey.GetPublic().Encrypt(readKey.Bytes()) + if err != nil { + return + } + + // preparing acl + aclRoot := &aclrecordproto.ACLRoot{ + Identity: identity, + EncryptionKey: encPubKey, + SpaceId: spaceId, + EncryptedReadKey: encReadKey, + DerivationScheme: "", + CurrentReadKeyHash: readKeyHash, + Timestamp: time.Now().UnixNano(), + } + rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey) + if err != nil { + return + } + + // creating storage + storagePayload = storage.SpaceStorageCreatePayload{ + RecWithId: rawWithId, + SpaceHeader: header, + Id: id, + } + return +} + +func marshalACLRoot(aclRoot *aclrecordproto.ACLRoot, key signingkey.PrivKey) (rawWithId *aclrecordproto.RawACLRecordWithId, err error) { + marshalledRoot, err := aclRoot.Marshal() + if err != nil { + return + } + signature, err := key.Sign(marshalledRoot) + if err != nil { + return + } + raw := &aclrecordproto.RawACLRecord{ + Payload: marshalledRoot, + Signature: signature, + } + marshalledRaw, err := raw.Marshal() + if err != nil { + return + } + aclHeadId, err := cid.NewCIDFromBytes(marshalledRaw) + if err != nil { + return + } + rawWithId = &aclrecordproto.RawACLRecordWithId{ + Payload: marshalledRaw, + Id: aclHeadId, + } + return +} diff --git a/common/commonspace/service.go b/common/commonspace/service.go index 48f4b4cf..ef287659 100644 --- a/common/commonspace/service.go +++ b/common/commonspace/service.go @@ -6,17 +6,10 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice" - "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/config" - "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto" - "github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid" - "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey" - "hash/fnv" - "math/rand" - "time" ) const CName = "common.commonspace" @@ -57,171 +50,32 @@ func (s *service) CreateSpace( ctx context.Context, cache cache.TreeCache, payload SpaceCreatePayload) (sp Space, err error) { - - // unmarshalling signing and encryption keys - identity, err := payload.SigningKey.GetPublic().Raw() + storageCreate, err := storagePayloadForSpaceCreate(payload) if err != nil { return } - encPubKey, err := payload.EncryptionKey.GetPublic().Raw() - if err != nil { - return - } - - // preparing header and space id - bytes := make([]byte, 32) - _, err = rand.Read(bytes) - if err != nil { - return - } - header := &spacesyncproto.SpaceHeader{ - Identity: identity, - Timestamp: time.Now().UnixNano(), - SpaceType: payload.SpaceType, - ReplicationKey: payload.ReplicationKey, - Seed: bytes, - } - marshalled, err := header.Marshal() - if err != nil { - return - } - id, err := cid.NewCIDFromBytes(marshalled) - if err != nil { - return - } - spaceId := NewSpaceId(id, payload.ReplicationKey) - - // encrypting read key - hasher := fnv.New64() - _, err = hasher.Write(payload.ReadKey) - if err != nil { - return - } - readKeyHash := hasher.Sum64() - encReadKey, err := payload.EncryptionKey.GetPublic().Encrypt(payload.ReadKey) - if err != nil { - return - } - - // preparing acl - aclRoot := &aclrecordproto.ACLRoot{ - Identity: identity, - EncryptionKey: encPubKey, - SpaceId: spaceId, - EncryptedReadKey: encReadKey, - DerivationScheme: "", - CurrentReadKeyHash: readKeyHash, - Timestamp: time.Now().UnixNano(), - } - rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey) - if err != nil { - return - } - - // creating storage - storageCreate := storage.SpaceStorageCreatePayload{ - RecWithId: rawWithId, - SpaceHeader: header, - Id: id, - } _, err = s.storageProvider.CreateSpaceStorage(storageCreate) if err != nil { return } - return s.GetSpace(ctx, spaceId) + return s.GetSpace(ctx, storageCreate.Id) } func (s *service) DeriveSpace( ctx context.Context, cache cache.TreeCache, payload SpaceDerivePayload) (sp Space, err error) { - - // unmarshalling signing and encryption keys - identity, err := payload.SigningKey.GetPublic().Raw() + storageCreate, err := storagePayloadForSpaceDerive(payload) if err != nil { return } - signPrivKey, err := payload.SigningKey.Raw() - if err != nil { - return - } - encPubKey, err := payload.EncryptionKey.GetPublic().Raw() - if err != nil { - return - } - encPrivKey, err := payload.EncryptionKey.Raw() - if err != nil { - return - } - - // preparing replication key - hasher := fnv.New64() - _, err = hasher.Write(identity) - if err != nil { - return - } - repKey := hasher.Sum64() - - // preparing header and space id - header := &spacesyncproto.SpaceHeader{ - Identity: identity, - SpaceType: SpaceTypeDerived, - ReplicationKey: repKey, - } - marshalled, err := header.Marshal() - if err != nil { - return - } - id, err := cid.NewCIDFromBytes(marshalled) - if err != nil { - return - } - spaceId := NewSpaceId(id, repKey) - - // deriving and encrypting read key - readKey, err := aclrecordproto.ACLReadKeyDerive(signPrivKey, encPrivKey) - if err != nil { - return - } - hasher = fnv.New64() - _, err = hasher.Write(readKey.Bytes()) - if err != nil { - return - } - readKeyHash := hasher.Sum64() - encReadKey, err := payload.EncryptionKey.GetPublic().Encrypt(readKey.Bytes()) - if err != nil { - return - } - - // preparing acl - aclRoot := &aclrecordproto.ACLRoot{ - Identity: identity, - EncryptionKey: encPubKey, - SpaceId: spaceId, - EncryptedReadKey: encReadKey, - DerivationScheme: "", - CurrentReadKeyHash: readKeyHash, - Timestamp: time.Now().UnixNano(), - } - rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey) - if err != nil { - return - } - - // creating storage - storageCreate := storage.SpaceStorageCreatePayload{ - RecWithId: rawWithId, - SpaceHeader: header, - Id: id, - } _, err = s.storageProvider.CreateSpaceStorage(storageCreate) if err != nil { return } - return s.GetSpace(ctx, spaceId) + return s.GetSpace(ctx, storageCreate.Id) } func (s *service) GetSpace(ctx context.Context, id string) (Space, error) { @@ -244,31 +98,3 @@ func (s *service) GetSpace(ctx context.Context, id string) (Space, error) { } return sp, nil } - -func marshalACLRoot(aclRoot *aclrecordproto.ACLRoot, key signingkey.PrivKey) (rawWithId *aclrecordproto.RawACLRecordWithId, err error) { - marshalledRoot, err := aclRoot.Marshal() - if err != nil { - return - } - signature, err := key.Sign(marshalledRoot) - if err != nil { - return - } - raw := &aclrecordproto.RawACLRecord{ - Payload: marshalledRoot, - Signature: signature, - } - marshalledRaw, err := raw.Marshal() - if err != nil { - return - } - aclHeadId, err := cid.NewCIDFromBytes(marshalledRaw) - if err != nil { - return - } - rawWithId = &aclrecordproto.RawACLRecordWithId{ - Payload: marshalledRaw, - Id: aclHeadId, - } - return -} diff --git a/common/commonspace/spacesyncproto/spacesync.go b/common/commonspace/spacesyncproto/spacesync.go index 2e22737a..d06102c4 100644 --- a/common/commonspace/spacesyncproto/spacesync.go +++ b/common/commonspace/spacesyncproto/spacesync.go @@ -1,9 +1,22 @@ package spacesyncproto -import "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" +import ( + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" + "storj.io/drpc" +) type SpaceStream = DRPCSpace_StreamStream +type ClientFactoryFunc func(cc drpc.Conn) DRPCSpaceClient + +func (c ClientFactoryFunc) Client(cc drpc.Conn) DRPCSpaceClient { + return c(cc) +} + +type ClientFactory interface { + Client(cc drpc.Conn) DRPCSpaceClient +} + func WrapHeadUpdate(update *ObjectHeadUpdate, rootChange *treechangeproto.RawTreeChangeWithId, treeId, trackingId string) *ObjectSyncMessage { return &ObjectSyncMessage{ Content: &ObjectSyncContentValue{ diff --git a/common/commonspace/syncservice/syncservice.go b/common/commonspace/syncservice/syncservice.go index 0d9bf722..64ac67a6 100644 --- a/common/commonspace/syncservice/syncservice.go +++ b/common/commonspace/syncservice/syncservice.go @@ -38,6 +38,7 @@ type syncService struct { streamPool StreamPool headNotifiable HeadNotifiable configuration nodeconf.Configuration + clientFactory spacesyncproto.ClientFactory streamLoopCtx context.Context stopStreamLoop context.CancelFunc @@ -50,7 +51,13 @@ func NewSyncService(spaceId string, headNotifiable HeadNotifiable, cache cache.T return syncHandler.HandleMessage(ctx, senderId, message) }) syncHandler = newSyncHandler(spaceId, cache, streamPool) - return newSyncService(spaceId, headNotifiable, syncHandler, streamPool, configuration) + return newSyncService( + spaceId, + headNotifiable, + syncHandler, + streamPool, + spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient), + configuration) } func newSyncService( @@ -58,12 +65,14 @@ func newSyncService( headNotifiable HeadNotifiable, syncHandler SyncHandler, streamPool StreamPool, + clientFactory spacesyncproto.ClientFactory, configuration nodeconf.Configuration) *syncService { return &syncService{ syncHandler: syncHandler, streamPool: streamPool, headNotifiable: headNotifiable, configuration: configuration, + clientFactory: clientFactory, spaceId: spaceId, streamLoopDone: make(chan struct{}), } @@ -100,8 +109,7 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) { if s.streamPool.HasActiveStream(peer.Id()) { continue } - cl := spacesyncproto.NewDRPCSpaceClient(peer) - stream, err := cl.Stream(ctx) + stream, err := s.clientFactory.Client(peer).Stream(ctx) if err != nil { err = rpcerr.Unwrap(err) log.With("spaceId", s.spaceId).Errorf("failed to open stream: %v", err) From b9c942410337323281a56bde66bed061eed3c1e0 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Fri, 30 Sep 2022 13:49:31 +0200 Subject: [PATCH 03/17] Add mock to write diffservice tests --- Makefile | 7 +- common/commonspace/cache/treecache.go | 1 + common/commonspace/cache/treecache_mock.go | 107 +++++++ .../diffservice/diffsyncer_test.go | 34 ++ .../spacesyncproto/drpcspaceclient_mock.go | 95 ++++++ .../commonspace/spacesyncproto/spacesync.go | 1 + common/commonspace/storage/storage.go | 1 + common/commonspace/storage/storage_mock.go | 193 ++++++++++++ common/nodeconf/configuration.go | 1 + common/nodeconf/configuration_mock.go | 123 ++++++++ go.mod | 8 +- go.sum | 6 + pkg/acl/list/list.go | 1 + pkg/acl/list/list_mock.go | 221 +++++++++++++ pkg/acl/tree/objecttree.go | 1 + pkg/acl/tree/objecttree_mock.go | 290 ++++++++++++++++++ pkg/ldiff/diff.go | 1 + pkg/ldiff/diff_mock.go | 135 ++++++++ 18 files changed, 1223 insertions(+), 3 deletions(-) create mode 100644 common/commonspace/cache/treecache_mock.go create mode 100644 common/commonspace/diffservice/diffsyncer_test.go create mode 100644 common/commonspace/spacesyncproto/drpcspaceclient_mock.go create mode 100644 common/commonspace/storage/storage_mock.go create mode 100644 common/nodeconf/configuration_mock.go create mode 100644 pkg/acl/list/list_mock.go create mode 100644 pkg/acl/tree/objecttree_mock.go create mode 100644 pkg/ldiff/diff_mock.go diff --git a/Makefile b/Makefile index 53ddd25b..ab14b8c4 100644 --- a/Makefile +++ b/Makefile @@ -33,4 +33,9 @@ proto: build: @$(eval FLAGS := $$(shell govvv -flags -pkg github.com/anytypeio/go-anytype-infrastructure-experiments/app)) - go build -v -o bin/anytype-node -ldflags "$(FLAGS)" cmd/node/node.go \ No newline at end of file + go build -v -o bin/anytype-node -ldflags "$(FLAGS)" cmd/node/node.go + +test-deps: + @echo 'Generating test mocks...' + @go install github.com/golang/mock/mockgen + @go generate ./... \ No newline at end of file diff --git a/common/commonspace/cache/treecache.go b/common/commonspace/cache/treecache.go index 9983231f..4f72f0fd 100644 --- a/common/commonspace/cache/treecache.go +++ b/common/commonspace/cache/treecache.go @@ -1,3 +1,4 @@ +//go:generate mockgen -package cache -destination treecache_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache TreeCache package cache import ( diff --git a/common/commonspace/cache/treecache_mock.go b/common/commonspace/cache/treecache_mock.go new file mode 100644 index 00000000..1a42b411 --- /dev/null +++ b/common/commonspace/cache/treecache_mock.go @@ -0,0 +1,107 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache (interfaces: TreeCache) + +// Package cache is a generated GoMock package. +package cache + +import ( + context "context" + reflect "reflect" + + app "github.com/anytypeio/go-anytype-infrastructure-experiments/app" + gomock "github.com/golang/mock/gomock" +) + +// MockTreeCache is a mock of TreeCache interface. +type MockTreeCache struct { + ctrl *gomock.Controller + recorder *MockTreeCacheMockRecorder +} + +// MockTreeCacheMockRecorder is the mock recorder for MockTreeCache. +type MockTreeCacheMockRecorder struct { + mock *MockTreeCache +} + +// NewMockTreeCache creates a new mock instance. +func NewMockTreeCache(ctrl *gomock.Controller) *MockTreeCache { + mock := &MockTreeCache{ctrl: ctrl} + mock.recorder = &MockTreeCacheMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockTreeCache) EXPECT() *MockTreeCacheMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockTreeCache) Close(arg0 context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockTreeCacheMockRecorder) Close(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockTreeCache)(nil).Close), arg0) +} + +// GetTree mocks base method. +func (m *MockTreeCache) GetTree(arg0 context.Context, arg1, arg2 string) (TreeResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTree", arg0, arg1, arg2) + ret0, _ := ret[0].(TreeResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTree indicates an expected call of GetTree. +func (mr *MockTreeCacheMockRecorder) GetTree(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTree", reflect.TypeOf((*MockTreeCache)(nil).GetTree), arg0, arg1, arg2) +} + +// Init mocks base method. +func (m *MockTreeCache) Init(arg0 *app.App) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Init", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Init indicates an expected call of Init. +func (mr *MockTreeCacheMockRecorder) Init(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockTreeCache)(nil).Init), arg0) +} + +// Name mocks base method. +func (m *MockTreeCache) Name() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Name") + ret0, _ := ret[0].(string) + return ret0 +} + +// Name indicates an expected call of Name. +func (mr *MockTreeCacheMockRecorder) Name() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockTreeCache)(nil).Name)) +} + +// Run mocks base method. +func (m *MockTreeCache) Run(arg0 context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Run", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Run indicates an expected call of Run. +func (mr *MockTreeCacheMockRecorder) Run(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockTreeCache)(nil).Run), arg0) +} diff --git a/common/commonspace/diffservice/diffsyncer_test.go b/common/commonspace/diffservice/diffsyncer_test.go new file mode 100644 index 00000000..af199c54 --- /dev/null +++ b/common/commonspace/diffservice/diffsyncer_test.go @@ -0,0 +1,34 @@ +package diffservice + +import ( + "context" + "github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff" + "github.com/golang/mock/gomock" + "storj.io/drpc" + "testing" +) + +func TestDiffSyncer_Sync(t *testing.T) { + // setup + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + diffMock := ldiff.NewMockDiff(ctrl) + nconfMock := nodeconf.NewMockConfiguration(ctrl) + cacheMock := cache.NewMockTreeCache(ctrl) + stMock := storage.NewMockSpaceStorage(ctrl) + clientMock := spacesyncproto.NewMockDRPCSpaceClient(ctrl) + factory := spacesyncproto.ClientFactoryFunc(func(cc drpc.Conn) spacesyncproto.DRPCSpaceClient { + return clientMock + }) + spaceId := "spaceId" + l := logger.NewNamed(spaceId) + diffSyncer := newDiffSyncer(spaceId, diffMock, nconfMock, cacheMock, stMock, factory, l) + diffSyncer.Sync(ctx) +} diff --git a/common/commonspace/spacesyncproto/drpcspaceclient_mock.go b/common/commonspace/spacesyncproto/drpcspaceclient_mock.go new file mode 100644 index 00000000..4e8fd108 --- /dev/null +++ b/common/commonspace/spacesyncproto/drpcspaceclient_mock.go @@ -0,0 +1,95 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto (interfaces: DRPCSpaceClient) + +// Package spacesyncproto is a generated GoMock package. +package spacesyncproto + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + drpc "storj.io/drpc" +) + +// MockDRPCSpaceClient is a mock of DRPCSpaceClient interface. +type MockDRPCSpaceClient struct { + ctrl *gomock.Controller + recorder *MockDRPCSpaceClientMockRecorder +} + +// MockDRPCSpaceClientMockRecorder is the mock recorder for MockDRPCSpaceClient. +type MockDRPCSpaceClientMockRecorder struct { + mock *MockDRPCSpaceClient +} + +// NewMockDRPCSpaceClient creates a new mock instance. +func NewMockDRPCSpaceClient(ctrl *gomock.Controller) *MockDRPCSpaceClient { + mock := &MockDRPCSpaceClient{ctrl: ctrl} + mock.recorder = &MockDRPCSpaceClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDRPCSpaceClient) EXPECT() *MockDRPCSpaceClientMockRecorder { + return m.recorder +} + +// DRPCConn mocks base method. +func (m *MockDRPCSpaceClient) DRPCConn() drpc.Conn { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DRPCConn") + ret0, _ := ret[0].(drpc.Conn) + return ret0 +} + +// DRPCConn indicates an expected call of DRPCConn. +func (mr *MockDRPCSpaceClientMockRecorder) DRPCConn() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DRPCConn", reflect.TypeOf((*MockDRPCSpaceClient)(nil).DRPCConn)) +} + +// HeadSync mocks base method. +func (m *MockDRPCSpaceClient) HeadSync(arg0 context.Context, arg1 *HeadSyncRequest) (*HeadSyncResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HeadSync", arg0, arg1) + ret0, _ := ret[0].(*HeadSyncResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// HeadSync indicates an expected call of HeadSync. +func (mr *MockDRPCSpaceClientMockRecorder) HeadSync(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeadSync", reflect.TypeOf((*MockDRPCSpaceClient)(nil).HeadSync), arg0, arg1) +} + +// PushSpace mocks base method. +func (m *MockDRPCSpaceClient) PushSpace(arg0 context.Context, arg1 *PushSpaceRequest) (*PushSpaceResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PushSpace", arg0, arg1) + ret0, _ := ret[0].(*PushSpaceResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PushSpace indicates an expected call of PushSpace. +func (mr *MockDRPCSpaceClientMockRecorder) PushSpace(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PushSpace", reflect.TypeOf((*MockDRPCSpaceClient)(nil).PushSpace), arg0, arg1) +} + +// Stream mocks base method. +func (m *MockDRPCSpaceClient) Stream(arg0 context.Context) (DRPCSpace_StreamClient, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Stream", arg0) + ret0, _ := ret[0].(DRPCSpace_StreamClient) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Stream indicates an expected call of Stream. +func (mr *MockDRPCSpaceClientMockRecorder) Stream(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stream", reflect.TypeOf((*MockDRPCSpaceClient)(nil).Stream), arg0) +} diff --git a/common/commonspace/spacesyncproto/spacesync.go b/common/commonspace/spacesyncproto/spacesync.go index d06102c4..e7924694 100644 --- a/common/commonspace/spacesyncproto/spacesync.go +++ b/common/commonspace/spacesyncproto/spacesync.go @@ -1,3 +1,4 @@ +//go:generate mockgen -package spacesyncproto -destination drpcspaceclient_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto DRPCSpaceClient package spacesyncproto import ( diff --git a/common/commonspace/storage/storage.go b/common/commonspace/storage/storage.go index add06e08..60d852e6 100644 --- a/common/commonspace/storage/storage.go +++ b/common/commonspace/storage/storage.go @@ -1,3 +1,4 @@ +//go:generate mockgen -package storage -destination storage_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage SpaceStorageProvider,SpaceStorage package storage import ( diff --git a/common/commonspace/storage/storage_mock.go b/common/commonspace/storage/storage_mock.go new file mode 100644 index 00000000..c671fbad --- /dev/null +++ b/common/commonspace/storage/storage_mock.go @@ -0,0 +1,193 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage (interfaces: SpaceStorageProvider,SpaceStorage) + +// Package storage is a generated GoMock package. +package storage + +import ( + reflect "reflect" + + app "github.com/anytypeio/go-anytype-infrastructure-experiments/app" + spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" + storage0 "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" + gomock "github.com/golang/mock/gomock" +) + +// MockSpaceStorageProvider is a mock of SpaceStorageProvider interface. +type MockSpaceStorageProvider struct { + ctrl *gomock.Controller + recorder *MockSpaceStorageProviderMockRecorder +} + +// MockSpaceStorageProviderMockRecorder is the mock recorder for MockSpaceStorageProvider. +type MockSpaceStorageProviderMockRecorder struct { + mock *MockSpaceStorageProvider +} + +// NewMockSpaceStorageProvider creates a new mock instance. +func NewMockSpaceStorageProvider(ctrl *gomock.Controller) *MockSpaceStorageProvider { + mock := &MockSpaceStorageProvider{ctrl: ctrl} + mock.recorder = &MockSpaceStorageProviderMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockSpaceStorageProvider) EXPECT() *MockSpaceStorageProviderMockRecorder { + return m.recorder +} + +// CreateSpaceStorage mocks base method. +func (m *MockSpaceStorageProvider) CreateSpaceStorage(arg0 SpaceStorageCreatePayload) (SpaceStorage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateSpaceStorage", arg0) + ret0, _ := ret[0].(SpaceStorage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateSpaceStorage indicates an expected call of CreateSpaceStorage. +func (mr *MockSpaceStorageProviderMockRecorder) CreateSpaceStorage(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSpaceStorage", reflect.TypeOf((*MockSpaceStorageProvider)(nil).CreateSpaceStorage), arg0) +} + +// Init mocks base method. +func (m *MockSpaceStorageProvider) Init(arg0 *app.App) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Init", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Init indicates an expected call of Init. +func (mr *MockSpaceStorageProviderMockRecorder) Init(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockSpaceStorageProvider)(nil).Init), arg0) +} + +// Name mocks base method. +func (m *MockSpaceStorageProvider) Name() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Name") + ret0, _ := ret[0].(string) + return ret0 +} + +// Name indicates an expected call of Name. +func (mr *MockSpaceStorageProviderMockRecorder) Name() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockSpaceStorageProvider)(nil).Name)) +} + +// SpaceStorage mocks base method. +func (m *MockSpaceStorageProvider) SpaceStorage(arg0 string) (SpaceStorage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SpaceStorage", arg0) + ret0, _ := ret[0].(SpaceStorage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SpaceStorage indicates an expected call of SpaceStorage. +func (mr *MockSpaceStorageProviderMockRecorder) SpaceStorage(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpaceStorage", reflect.TypeOf((*MockSpaceStorageProvider)(nil).SpaceStorage), arg0) +} + +// MockSpaceStorage is a mock of SpaceStorage interface. +type MockSpaceStorage struct { + ctrl *gomock.Controller + recorder *MockSpaceStorageMockRecorder +} + +// MockSpaceStorageMockRecorder is the mock recorder for MockSpaceStorage. +type MockSpaceStorageMockRecorder struct { + mock *MockSpaceStorage +} + +// NewMockSpaceStorage creates a new mock instance. +func NewMockSpaceStorage(ctrl *gomock.Controller) *MockSpaceStorage { + mock := &MockSpaceStorage{ctrl: ctrl} + mock.recorder = &MockSpaceStorageMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockSpaceStorage) EXPECT() *MockSpaceStorageMockRecorder { + return m.recorder +} + +// ACLStorage mocks base method. +func (m *MockSpaceStorage) ACLStorage() (storage0.ListStorage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ACLStorage") + ret0, _ := ret[0].(storage0.ListStorage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ACLStorage indicates an expected call of ACLStorage. +func (mr *MockSpaceStorageMockRecorder) ACLStorage() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ACLStorage", reflect.TypeOf((*MockSpaceStorage)(nil).ACLStorage)) +} + +// CreateTreeStorage mocks base method. +func (m *MockSpaceStorage) CreateTreeStorage(arg0 storage0.TreeStorageCreatePayload) (storage0.TreeStorage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateTreeStorage", arg0) + ret0, _ := ret[0].(storage0.TreeStorage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateTreeStorage indicates an expected call of CreateTreeStorage. +func (mr *MockSpaceStorageMockRecorder) CreateTreeStorage(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTreeStorage", reflect.TypeOf((*MockSpaceStorage)(nil).CreateTreeStorage), arg0) +} + +// SpaceHeader mocks base method. +func (m *MockSpaceStorage) SpaceHeader() (*spacesyncproto.SpaceHeader, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SpaceHeader") + ret0, _ := ret[0].(*spacesyncproto.SpaceHeader) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SpaceHeader indicates an expected call of SpaceHeader. +func (mr *MockSpaceStorageMockRecorder) SpaceHeader() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpaceHeader", reflect.TypeOf((*MockSpaceStorage)(nil).SpaceHeader)) +} + +// StoredIds mocks base method. +func (m *MockSpaceStorage) StoredIds() ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StoredIds") + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StoredIds indicates an expected call of StoredIds. +func (mr *MockSpaceStorageMockRecorder) StoredIds() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoredIds", reflect.TypeOf((*MockSpaceStorage)(nil).StoredIds)) +} + +// TreeStorage mocks base method. +func (m *MockSpaceStorage) TreeStorage(arg0 string) (storage0.TreeStorage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TreeStorage", arg0) + ret0, _ := ret[0].(storage0.TreeStorage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// TreeStorage indicates an expected call of TreeStorage. +func (mr *MockSpaceStorageMockRecorder) TreeStorage(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TreeStorage", reflect.TypeOf((*MockSpaceStorage)(nil).TreeStorage), arg0) +} diff --git a/common/nodeconf/configuration.go b/common/nodeconf/configuration.go index 597d1018..cb169103 100644 --- a/common/nodeconf/configuration.go +++ b/common/nodeconf/configuration.go @@ -1,3 +1,4 @@ +//go:generate mockgen -package nodeconf -destination configuration_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf Configuration package nodeconf import ( diff --git a/common/nodeconf/configuration_mock.go b/common/nodeconf/configuration_mock.go new file mode 100644 index 00000000..c84e1848 --- /dev/null +++ b/common/nodeconf/configuration_mock.go @@ -0,0 +1,123 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf (interfaces: Configuration) + +// Package nodeconf is a generated GoMock package. +package nodeconf + +import ( + context "context" + reflect "reflect" + + peer "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer" + gomock "github.com/golang/mock/gomock" +) + +// MockConfiguration is a mock of Configuration interface. +type MockConfiguration struct { + ctrl *gomock.Controller + recorder *MockConfigurationMockRecorder +} + +// MockConfigurationMockRecorder is the mock recorder for MockConfiguration. +type MockConfigurationMockRecorder struct { + mock *MockConfiguration +} + +// NewMockConfiguration creates a new mock instance. +func NewMockConfiguration(ctrl *gomock.Controller) *MockConfiguration { + mock := &MockConfiguration{ctrl: ctrl} + mock.recorder = &MockConfigurationMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockConfiguration) EXPECT() *MockConfigurationMockRecorder { + return m.recorder +} + +// AllPeers mocks base method. +func (m *MockConfiguration) AllPeers(arg0 context.Context, arg1 string) ([]peer.Peer, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AllPeers", arg0, arg1) + ret0, _ := ret[0].([]peer.Peer) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AllPeers indicates an expected call of AllPeers. +func (mr *MockConfigurationMockRecorder) AllPeers(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllPeers", reflect.TypeOf((*MockConfiguration)(nil).AllPeers), arg0, arg1) +} + +// Id mocks base method. +func (m *MockConfiguration) Id() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Id") + ret0, _ := ret[0].(string) + return ret0 +} + +// Id indicates an expected call of Id. +func (mr *MockConfigurationMockRecorder) Id() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockConfiguration)(nil).Id)) +} + +// IsResponsible mocks base method. +func (m *MockConfiguration) IsResponsible(arg0 string) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsResponsible", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsResponsible indicates an expected call of IsResponsible. +func (mr *MockConfigurationMockRecorder) IsResponsible(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsResponsible", reflect.TypeOf((*MockConfiguration)(nil).IsResponsible), arg0) +} + +// NodeIds mocks base method. +func (m *MockConfiguration) NodeIds(arg0 string) []string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NodeIds", arg0) + ret0, _ := ret[0].([]string) + return ret0 +} + +// NodeIds indicates an expected call of NodeIds. +func (mr *MockConfigurationMockRecorder) NodeIds(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeIds", reflect.TypeOf((*MockConfiguration)(nil).NodeIds), arg0) +} + +// OnePeer mocks base method. +func (m *MockConfiguration) OnePeer(arg0 context.Context, arg1 string) (peer.Peer, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnePeer", arg0, arg1) + ret0, _ := ret[0].(peer.Peer) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OnePeer indicates an expected call of OnePeer. +func (mr *MockConfigurationMockRecorder) OnePeer(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnePeer", reflect.TypeOf((*MockConfiguration)(nil).OnePeer), arg0, arg1) +} + +// ResponsiblePeers mocks base method. +func (m *MockConfiguration) ResponsiblePeers(arg0 context.Context, arg1 string) ([]peer.Peer, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ResponsiblePeers", arg0, arg1) + ret0, _ := ret[0].([]peer.Peer) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ResponsiblePeers indicates an expected call of ResponsiblePeers. +func (mr *MockConfigurationMockRecorder) ResponsiblePeers(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResponsiblePeers", reflect.TypeOf((*MockConfiguration)(nil).ResponsiblePeers), arg0, arg1) +} diff --git a/go.mod b/go.mod index 9c60aa54..65064b7d 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/ipfs/go-cid v0.1.0 github.com/libp2p/go-libp2p v0.20.3 github.com/libp2p/go-libp2p-core v0.16.1 - github.com/mr-tron/base58 v1.2.0 + github.com/minio/sha256-simd v1.0.0 github.com/multiformats/go-multibase v0.0.3 github.com/multiformats/go-multihash v0.1.0 github.com/stretchr/testify v1.8.0 @@ -33,11 +33,12 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/fogleman/gg v1.3.0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/golang/mock v1.6.0 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/libp2p/go-buffer-pool v0.0.2 // indirect github.com/libp2p/go-openssl v0.0.7 // indirect github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect - github.com/minio/sha256-simd v1.0.0 // indirect + github.com/mr-tron/base58 v1.2.0 // indirect github.com/multiformats/go-base32 v0.0.3 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect github.com/multiformats/go-multiaddr v0.5.0 // indirect @@ -51,7 +52,10 @@ require ( go.uber.org/multierr v1.8.0 // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect golang.org/x/image v0.0.0-20200119044424-58c23975cae1 // indirect + golang.org/x/mod v0.4.2 // indirect golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect + golang.org/x/tools v0.1.5 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect lukechampine.com/blake3 v1.1.6 // indirect diff --git a/go.sum b/go.sum index 34c05834..8982483e 100644 --- a/go.sum +++ b/go.sum @@ -32,6 +32,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw= @@ -141,6 +143,7 @@ golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+o golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -173,10 +176,13 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/acl/list/list.go b/pkg/acl/list/list.go index 46a48681..0e2a31ed 100644 --- a/pkg/acl/list/list.go +++ b/pkg/acl/list/list.go @@ -1,3 +1,4 @@ +//go:generate mockgen -package list -destination list_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list ACLList package list import ( diff --git a/pkg/acl/list/list_mock.go b/pkg/acl/list/list_mock.go new file mode 100644 index 00000000..215ca59e --- /dev/null +++ b/pkg/acl/list/list_mock.go @@ -0,0 +1,221 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list (interfaces: ACLList) + +// Package list is a generated GoMock package. +package list + +import ( + reflect "reflect" + + aclrecordproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto" + gomock "github.com/golang/mock/gomock" +) + +// MockACLList is a mock of ACLList interface. +type MockACLList struct { + ctrl *gomock.Controller + recorder *MockACLListMockRecorder +} + +// MockACLListMockRecorder is the mock recorder for MockACLList. +type MockACLListMockRecorder struct { + mock *MockACLList +} + +// NewMockACLList creates a new mock instance. +func NewMockACLList(ctrl *gomock.Controller) *MockACLList { + mock := &MockACLList{ctrl: ctrl} + mock.recorder = &MockACLListMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockACLList) EXPECT() *MockACLListMockRecorder { + return m.recorder +} + +// ACLState mocks base method. +func (m *MockACLList) ACLState() *ACLState { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ACLState") + ret0, _ := ret[0].(*ACLState) + return ret0 +} + +// ACLState indicates an expected call of ACLState. +func (mr *MockACLListMockRecorder) ACLState() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ACLState", reflect.TypeOf((*MockACLList)(nil).ACLState)) +} + +// Close mocks base method. +func (m *MockACLList) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockACLListMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockACLList)(nil).Close)) +} + +// Get mocks base method. +func (m *MockACLList) Get(arg0 string) (*ACLRecord, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0) + ret0, _ := ret[0].(*ACLRecord) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockACLListMockRecorder) Get(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockACLList)(nil).Get), arg0) +} + +// Head mocks base method. +func (m *MockACLList) Head() *ACLRecord { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Head") + ret0, _ := ret[0].(*ACLRecord) + return ret0 +} + +// Head indicates an expected call of Head. +func (mr *MockACLListMockRecorder) Head() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Head", reflect.TypeOf((*MockACLList)(nil).Head)) +} + +// ID mocks base method. +func (m *MockACLList) ID() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ID") + ret0, _ := ret[0].(string) + return ret0 +} + +// ID indicates an expected call of ID. +func (mr *MockACLListMockRecorder) ID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockACLList)(nil).ID)) +} + +// IsAfter mocks base method. +func (m *MockACLList) IsAfter(arg0, arg1 string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsAfter", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// IsAfter indicates an expected call of IsAfter. +func (mr *MockACLListMockRecorder) IsAfter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAfter", reflect.TypeOf((*MockACLList)(nil).IsAfter), arg0, arg1) +} + +// Iterate mocks base method. +func (m *MockACLList) Iterate(arg0 func(*ACLRecord) bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Iterate", arg0) +} + +// Iterate indicates an expected call of Iterate. +func (mr *MockACLListMockRecorder) Iterate(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterate", reflect.TypeOf((*MockACLList)(nil).Iterate), arg0) +} + +// IterateFrom mocks base method. +func (m *MockACLList) IterateFrom(arg0 string, arg1 func(*ACLRecord) bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "IterateFrom", arg0, arg1) +} + +// IterateFrom indicates an expected call of IterateFrom. +func (mr *MockACLListMockRecorder) IterateFrom(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateFrom", reflect.TypeOf((*MockACLList)(nil).IterateFrom), arg0, arg1) +} + +// Lock mocks base method. +func (m *MockACLList) Lock() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Lock") +} + +// Lock indicates an expected call of Lock. +func (mr *MockACLListMockRecorder) Lock() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Lock", reflect.TypeOf((*MockACLList)(nil).Lock)) +} + +// RLock mocks base method. +func (m *MockACLList) RLock() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RLock") +} + +// RLock indicates an expected call of RLock. +func (mr *MockACLListMockRecorder) RLock() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RLock", reflect.TypeOf((*MockACLList)(nil).RLock)) +} + +// RUnlock mocks base method. +func (m *MockACLList) RUnlock() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RUnlock") +} + +// RUnlock indicates an expected call of RUnlock. +func (mr *MockACLListMockRecorder) RUnlock() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RUnlock", reflect.TypeOf((*MockACLList)(nil).RUnlock)) +} + +// Records mocks base method. +func (m *MockACLList) Records() []*ACLRecord { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Records") + ret0, _ := ret[0].([]*ACLRecord) + return ret0 +} + +// Records indicates an expected call of Records. +func (mr *MockACLListMockRecorder) Records() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Records", reflect.TypeOf((*MockACLList)(nil).Records)) +} + +// Root mocks base method. +func (m *MockACLList) Root() *aclrecordproto.ACLRoot { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Root") + ret0, _ := ret[0].(*aclrecordproto.ACLRoot) + return ret0 +} + +// Root indicates an expected call of Root. +func (mr *MockACLListMockRecorder) Root() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockACLList)(nil).Root)) +} + +// Unlock mocks base method. +func (m *MockACLList) Unlock() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Unlock") +} + +// Unlock indicates an expected call of Unlock. +func (mr *MockACLListMockRecorder) Unlock() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unlock", reflect.TypeOf((*MockACLList)(nil).Unlock)) +} diff --git a/pkg/acl/tree/objecttree.go b/pkg/acl/tree/objecttree.go index bb342070..95348feb 100644 --- a/pkg/acl/tree/objecttree.go +++ b/pkg/acl/tree/objecttree.go @@ -1,3 +1,4 @@ +//go:generate mockgen -package tree -destination objecttree_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree ObjectTree package tree import ( diff --git a/pkg/acl/tree/objecttree_mock.go b/pkg/acl/tree/objecttree_mock.go new file mode 100644 index 00000000..5632850d --- /dev/null +++ b/pkg/acl/tree/objecttree_mock.go @@ -0,0 +1,290 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree (interfaces: ObjectTree) + +// Package tree is a generated GoMock package. +package tree + +import ( + context "context" + reflect "reflect" + + storage "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" + treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" + gomock "github.com/golang/mock/gomock" +) + +// MockObjectTree is a mock of ObjectTree interface. +type MockObjectTree struct { + ctrl *gomock.Controller + recorder *MockObjectTreeMockRecorder +} + +// MockObjectTreeMockRecorder is the mock recorder for MockObjectTree. +type MockObjectTreeMockRecorder struct { + mock *MockObjectTree +} + +// NewMockObjectTree creates a new mock instance. +func NewMockObjectTree(ctrl *gomock.Controller) *MockObjectTree { + mock := &MockObjectTree{ctrl: ctrl} + mock.recorder = &MockObjectTreeMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockObjectTree) EXPECT() *MockObjectTreeMockRecorder { + return m.recorder +} + +// AddContent mocks base method. +func (m *MockObjectTree) AddContent(arg0 context.Context, arg1 SignableChangeContent) (AddResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddContent", arg0, arg1) + ret0, _ := ret[0].(AddResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AddContent indicates an expected call of AddContent. +func (mr *MockObjectTreeMockRecorder) AddContent(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddContent", reflect.TypeOf((*MockObjectTree)(nil).AddContent), arg0, arg1) +} + +// AddRawChanges mocks base method. +func (m *MockObjectTree) AddRawChanges(arg0 context.Context, arg1 ...*treechangeproto.RawTreeChangeWithId) (AddResult, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "AddRawChanges", varargs...) + ret0, _ := ret[0].(AddResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AddRawChanges indicates an expected call of AddRawChanges. +func (mr *MockObjectTreeMockRecorder) AddRawChanges(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChanges", reflect.TypeOf((*MockObjectTree)(nil).AddRawChanges), varargs...) +} + +// ChangesAfterCommonSnapshot mocks base method. +func (m *MockObjectTree) ChangesAfterCommonSnapshot(arg0, arg1 []string) ([]*treechangeproto.RawTreeChangeWithId, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ChangesAfterCommonSnapshot", arg0, arg1) + ret0, _ := ret[0].([]*treechangeproto.RawTreeChangeWithId) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ChangesAfterCommonSnapshot indicates an expected call of ChangesAfterCommonSnapshot. +func (mr *MockObjectTreeMockRecorder) ChangesAfterCommonSnapshot(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangesAfterCommonSnapshot", reflect.TypeOf((*MockObjectTree)(nil).ChangesAfterCommonSnapshot), arg0, arg1) +} + +// Close mocks base method. +func (m *MockObjectTree) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockObjectTreeMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockObjectTree)(nil).Close)) +} + +// DebugDump mocks base method. +func (m *MockObjectTree) DebugDump() (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DebugDump") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DebugDump indicates an expected call of DebugDump. +func (mr *MockObjectTreeMockRecorder) DebugDump() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DebugDump", reflect.TypeOf((*MockObjectTree)(nil).DebugDump)) +} + +// HasChange mocks base method. +func (m *MockObjectTree) HasChange(arg0 string) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasChange", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// HasChange indicates an expected call of HasChange. +func (mr *MockObjectTreeMockRecorder) HasChange(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasChange", reflect.TypeOf((*MockObjectTree)(nil).HasChange), arg0) +} + +// Header mocks base method. +func (m *MockObjectTree) Header() *treechangeproto.RawTreeChangeWithId { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Header") + ret0, _ := ret[0].(*treechangeproto.RawTreeChangeWithId) + return ret0 +} + +// Header indicates an expected call of Header. +func (mr *MockObjectTreeMockRecorder) Header() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockObjectTree)(nil).Header)) +} + +// Heads mocks base method. +func (m *MockObjectTree) Heads() []string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Heads") + ret0, _ := ret[0].([]string) + return ret0 +} + +// Heads indicates an expected call of Heads. +func (mr *MockObjectTreeMockRecorder) Heads() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Heads", reflect.TypeOf((*MockObjectTree)(nil).Heads)) +} + +// ID mocks base method. +func (m *MockObjectTree) ID() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ID") + ret0, _ := ret[0].(string) + return ret0 +} + +// ID indicates an expected call of ID. +func (mr *MockObjectTreeMockRecorder) ID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockObjectTree)(nil).ID)) +} + +// Iterate mocks base method. +func (m *MockObjectTree) Iterate(arg0 func([]byte) (interface{}, error), arg1 func(*Change) bool) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Iterate", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Iterate indicates an expected call of Iterate. +func (mr *MockObjectTreeMockRecorder) Iterate(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterate", reflect.TypeOf((*MockObjectTree)(nil).Iterate), arg0, arg1) +} + +// IterateFrom mocks base method. +func (m *MockObjectTree) IterateFrom(arg0 string, arg1 func([]byte) (interface{}, error), arg2 func(*Change) bool) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IterateFrom", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// IterateFrom indicates an expected call of IterateFrom. +func (mr *MockObjectTreeMockRecorder) IterateFrom(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateFrom", reflect.TypeOf((*MockObjectTree)(nil).IterateFrom), arg0, arg1, arg2) +} + +// Lock mocks base method. +func (m *MockObjectTree) Lock() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Lock") +} + +// Lock indicates an expected call of Lock. +func (mr *MockObjectTreeMockRecorder) Lock() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Lock", reflect.TypeOf((*MockObjectTree)(nil).Lock)) +} + +// RLock mocks base method. +func (m *MockObjectTree) RLock() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RLock") +} + +// RLock indicates an expected call of RLock. +func (mr *MockObjectTreeMockRecorder) RLock() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RLock", reflect.TypeOf((*MockObjectTree)(nil).RLock)) +} + +// RUnlock mocks base method. +func (m *MockObjectTree) RUnlock() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RUnlock") +} + +// RUnlock indicates an expected call of RUnlock. +func (mr *MockObjectTreeMockRecorder) RUnlock() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RUnlock", reflect.TypeOf((*MockObjectTree)(nil).RUnlock)) +} + +// Root mocks base method. +func (m *MockObjectTree) Root() *Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Root") + ret0, _ := ret[0].(*Change) + return ret0 +} + +// Root indicates an expected call of Root. +func (mr *MockObjectTreeMockRecorder) Root() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockObjectTree)(nil).Root)) +} + +// SnapshotPath mocks base method. +func (m *MockObjectTree) SnapshotPath() []string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SnapshotPath") + ret0, _ := ret[0].([]string) + return ret0 +} + +// SnapshotPath indicates an expected call of SnapshotPath. +func (mr *MockObjectTreeMockRecorder) SnapshotPath() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SnapshotPath", reflect.TypeOf((*MockObjectTree)(nil).SnapshotPath)) +} + +// Storage mocks base method. +func (m *MockObjectTree) Storage() storage.TreeStorage { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Storage") + ret0, _ := ret[0].(storage.TreeStorage) + return ret0 +} + +// Storage indicates an expected call of Storage. +func (mr *MockObjectTreeMockRecorder) Storage() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Storage", reflect.TypeOf((*MockObjectTree)(nil).Storage)) +} + +// Unlock mocks base method. +func (m *MockObjectTree) Unlock() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Unlock") +} + +// Unlock indicates an expected call of Unlock. +func (mr *MockObjectTreeMockRecorder) Unlock() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unlock", reflect.TypeOf((*MockObjectTree)(nil).Unlock)) +} diff --git a/pkg/ldiff/diff.go b/pkg/ldiff/diff.go index 6f276afd..10346e45 100644 --- a/pkg/ldiff/diff.go +++ b/pkg/ldiff/diff.go @@ -1,3 +1,4 @@ +//go:generate mockgen -package ldiff -destination diff_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff Diff,Remote // Package ldiff provides a container of elements with fixed id and changeable content. // Diff can calculate the difference with another diff container (you can make it remote) with minimum hops and traffic. package ldiff diff --git a/pkg/ldiff/diff_mock.go b/pkg/ldiff/diff_mock.go new file mode 100644 index 00000000..e750af44 --- /dev/null +++ b/pkg/ldiff/diff_mock.go @@ -0,0 +1,135 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff (interfaces: Diff,Remote) + +// Package ldiff is a generated GoMock package. +package ldiff + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockDiff is a mock of Diff interface. +type MockDiff struct { + ctrl *gomock.Controller + recorder *MockDiffMockRecorder +} + +// MockDiffMockRecorder is the mock recorder for MockDiff. +type MockDiffMockRecorder struct { + mock *MockDiff +} + +// NewMockDiff creates a new mock instance. +func NewMockDiff(ctrl *gomock.Controller) *MockDiff { + mock := &MockDiff{ctrl: ctrl} + mock.recorder = &MockDiffMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDiff) EXPECT() *MockDiffMockRecorder { + return m.recorder +} + +// Diff mocks base method. +func (m *MockDiff) Diff(arg0 context.Context, arg1 Remote) ([]string, []string, []string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Diff", arg0, arg1) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].([]string) + ret2, _ := ret[2].([]string) + ret3, _ := ret[3].(error) + return ret0, ret1, ret2, ret3 +} + +// Diff indicates an expected call of Diff. +func (mr *MockDiffMockRecorder) Diff(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Diff", reflect.TypeOf((*MockDiff)(nil).Diff), arg0, arg1) +} + +// Ranges mocks base method. +func (m *MockDiff) Ranges(arg0 context.Context, arg1 []Range, arg2 []RangeResult) ([]RangeResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Ranges", arg0, arg1, arg2) + ret0, _ := ret[0].([]RangeResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Ranges indicates an expected call of Ranges. +func (mr *MockDiffMockRecorder) Ranges(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ranges", reflect.TypeOf((*MockDiff)(nil).Ranges), arg0, arg1, arg2) +} + +// RemoveId mocks base method. +func (m *MockDiff) RemoveId(arg0 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveId", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveId indicates an expected call of RemoveId. +func (mr *MockDiffMockRecorder) RemoveId(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveId", reflect.TypeOf((*MockDiff)(nil).RemoveId), arg0) +} + +// Set mocks base method. +func (m *MockDiff) Set(arg0 ...Element) { + m.ctrl.T.Helper() + varargs := []interface{}{} + for _, a := range arg0 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Set", varargs...) +} + +// Set indicates an expected call of Set. +func (mr *MockDiffMockRecorder) Set(arg0 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockDiff)(nil).Set), arg0...) +} + +// MockRemote is a mock of Remote interface. +type MockRemote struct { + ctrl *gomock.Controller + recorder *MockRemoteMockRecorder +} + +// MockRemoteMockRecorder is the mock recorder for MockRemote. +type MockRemoteMockRecorder struct { + mock *MockRemote +} + +// NewMockRemote creates a new mock instance. +func NewMockRemote(ctrl *gomock.Controller) *MockRemote { + mock := &MockRemote{ctrl: ctrl} + mock.recorder = &MockRemoteMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockRemote) EXPECT() *MockRemoteMockRecorder { + return m.recorder +} + +// Ranges mocks base method. +func (m *MockRemote) Ranges(arg0 context.Context, arg1 []Range, arg2 []RangeResult) ([]RangeResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Ranges", arg0, arg1, arg2) + ret0, _ := ret[0].([]RangeResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Ranges indicates an expected call of Ranges. +func (mr *MockRemoteMockRecorder) Ranges(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ranges", reflect.TypeOf((*MockRemote)(nil).Ranges), arg0, arg1, arg2) +} From 68ed132e61975ba29b17a8f4d942ee102bff37b0 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Fri, 30 Sep 2022 14:21:48 +0200 Subject: [PATCH 04/17] Make sync test --- common/commonspace/diffservice/diffsyncer.go | 13 +++++++------ .../diffservice/diffsyncer_test.go | 19 ++++++++++++++++++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/common/commonspace/diffservice/diffsyncer.go b/common/commonspace/diffservice/diffsyncer.go index 88cd00f4..8e354294 100644 --- a/common/commonspace/diffservice/diffsyncer.go +++ b/common/commonspace/diffservice/diffsyncer.go @@ -27,12 +27,13 @@ func newDiffSyncer( clientFactory spacesyncproto.ClientFactory, log *zap.Logger) DiffSyncer { return &diffSyncer{ - diff: diff, - nconf: nconf, - spaceId: spaceId, - cache: cache, - storage: storage, - log: log, + diff: diff, + nconf: nconf, + spaceId: spaceId, + cache: cache, + storage: storage, + clientFactory: clientFactory, + log: log, } } diff --git a/common/commonspace/diffservice/diffsyncer_test.go b/common/commonspace/diffservice/diffsyncer_test.go index af199c54..ffc610c8 100644 --- a/common/commonspace/diffservice/diffsyncer_test.go +++ b/common/commonspace/diffservice/diffsyncer_test.go @@ -4,8 +4,10 @@ import ( "context" "github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff" "github.com/golang/mock/gomock" @@ -30,5 +32,20 @@ func TestDiffSyncer_Sync(t *testing.T) { spaceId := "spaceId" l := logger.NewNamed(spaceId) diffSyncer := newDiffSyncer(spaceId, diffMock, nconfMock, cacheMock, stMock, factory, l) - diffSyncer.Sync(ctx) + + t.Run("diff syncer sync simple", func(t *testing.T) { + nconfMock.EXPECT(). + ResponsiblePeers(gomock.Any(), spaceId). + Return([]peer.Peer{nil}, nil) + diffMock.EXPECT(). + Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))). + Return([]string{"new"}, []string{"changed"}, nil, nil) + cacheMock.EXPECT(). + GetTree(gomock.Any(), spaceId, "new"). + Return(cache.TreeResult{}, nil) + cacheMock.EXPECT(). + GetTree(gomock.Any(), spaceId, "changed"). + Return(cache.TreeResult{}, nil) + _ = diffSyncer.Sync(ctx) + }) } From c01441460b717bd8ab49304b6ab606828ed45e2b Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Fri, 30 Sep 2022 14:41:36 +0200 Subject: [PATCH 05/17] Add push space custom matchers --- .../diffservice/diffsyncer_test.go | 70 ++++++++++- pkg/acl/storage/liststorage.go | 1 + pkg/acl/storage/liststorage_mock.go | 110 ++++++++++++++++++ 3 files changed, 175 insertions(+), 6 deletions(-) create mode 100644 pkg/acl/storage/liststorage_mock.go diff --git a/common/commonspace/diffservice/diffsyncer_test.go b/common/commonspace/diffservice/diffsyncer_test.go index ffc610c8..64d0abfd 100644 --- a/common/commonspace/diffservice/diffsyncer_test.go +++ b/common/commonspace/diffservice/diffsyncer_test.go @@ -9,12 +9,44 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto" + storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff" "github.com/golang/mock/gomock" "storj.io/drpc" "testing" ) +type pushSpaceRequestMatcher struct { + spaceId string + aclRoot *aclrecordproto.RawACLRecordWithId + spaceHeader *spacesyncproto.SpaceHeader +} + +func (p pushSpaceRequestMatcher) Matches(x interface{}) bool { + res, ok := x.(*spacesyncproto.PushSpaceRequest) + if !ok { + return false + } + + return res.SpaceId == p.spaceId && res.AclRoot == p.aclRoot && res.SpaceHeader == p.spaceHeader +} + +func (p pushSpaceRequestMatcher) String() string { + return "" +} + +func newPushSpaceRequestMatcher( + spaceId string, + aclRoot *aclrecordproto.RawACLRecordWithId, + spaceHeader *spacesyncproto.SpaceHeader) *pushSpaceRequestMatcher { + return &pushSpaceRequestMatcher{ + spaceId: spaceId, + aclRoot: aclRoot, + spaceHeader: spaceHeader, + } +} + func TestDiffSyncer_Sync(t *testing.T) { // setup ctx := context.Background() @@ -40,12 +72,38 @@ func TestDiffSyncer_Sync(t *testing.T) { diffMock.EXPECT(). Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))). Return([]string{"new"}, []string{"changed"}, nil, nil) - cacheMock.EXPECT(). - GetTree(gomock.Any(), spaceId, "new"). - Return(cache.TreeResult{}, nil) - cacheMock.EXPECT(). - GetTree(gomock.Any(), spaceId, "changed"). - Return(cache.TreeResult{}, nil) + for _, arg := range []string{"new", "changed"} { + cacheMock.EXPECT(). + GetTree(gomock.Any(), spaceId, arg). + Return(cache.TreeResult{}, nil) + } + _ = diffSyncer.Sync(ctx) + }) + + t.Run("diff syncer sync space missing", func(t *testing.T) { + aclStorageMock := storage2.NewMockListStorage(ctrl) + aclRoot := &aclrecordproto.RawACLRecordWithId{} + spaceHeader := &spacesyncproto.SpaceHeader{} + + nconfMock.EXPECT(). + ResponsiblePeers(gomock.Any(), spaceId). + Return([]peer.Peer{nil}, nil) + diffMock.EXPECT(). + Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))). + Return(nil, nil, nil, spacesyncproto.ErrSpaceMissing) + stMock.EXPECT(). + ACLStorage(). + Return(aclStorageMock, nil) + stMock.EXPECT(). + SpaceHeader(). + Return(spaceHeader, nil) + aclStorageMock.EXPECT(). + Root(). + Return(aclRoot, nil) + clientMock.EXPECT(). + PushSpace(gomock.Any(), newPushSpaceRequestMatcher(spaceId, aclRoot, spaceHeader)). + Return(nil, nil) + _ = diffSyncer.Sync(ctx) }) } diff --git a/pkg/acl/storage/liststorage.go b/pkg/acl/storage/liststorage.go index c4fe7d6e..19b4dfe1 100644 --- a/pkg/acl/storage/liststorage.go +++ b/pkg/acl/storage/liststorage.go @@ -1,3 +1,4 @@ +//go:generate mockgen -package storage -destination liststorage_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage ListStorage package storage import ( diff --git a/pkg/acl/storage/liststorage_mock.go b/pkg/acl/storage/liststorage_mock.go new file mode 100644 index 00000000..07a5ef80 --- /dev/null +++ b/pkg/acl/storage/liststorage_mock.go @@ -0,0 +1,110 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage (interfaces: ListStorage) + +// Package storage is a generated GoMock package. +package storage + +import ( + context "context" + reflect "reflect" + + aclrecordproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto" + gomock "github.com/golang/mock/gomock" +) + +// MockListStorage is a mock of ListStorage interface. +type MockListStorage struct { + ctrl *gomock.Controller + recorder *MockListStorageMockRecorder +} + +// MockListStorageMockRecorder is the mock recorder for MockListStorage. +type MockListStorageMockRecorder struct { + mock *MockListStorage +} + +// NewMockListStorage creates a new mock instance. +func NewMockListStorage(ctrl *gomock.Controller) *MockListStorage { + mock := &MockListStorage{ctrl: ctrl} + mock.recorder = &MockListStorageMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockListStorage) EXPECT() *MockListStorageMockRecorder { + return m.recorder +} + +// AddRawRecord mocks base method. +func (m *MockListStorage) AddRawRecord(arg0 context.Context, arg1 *aclrecordproto.RawACLRecordWithId) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddRawRecord", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddRawRecord indicates an expected call of AddRawRecord. +func (mr *MockListStorageMockRecorder) AddRawRecord(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawRecord", reflect.TypeOf((*MockListStorage)(nil).AddRawRecord), arg0, arg1) +} + +// GetRawRecord mocks base method. +func (m *MockListStorage) GetRawRecord(arg0 context.Context, arg1 string) (*aclrecordproto.RawACLRecordWithId, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRawRecord", arg0, arg1) + ret0, _ := ret[0].(*aclrecordproto.RawACLRecordWithId) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetRawRecord indicates an expected call of GetRawRecord. +func (mr *MockListStorageMockRecorder) GetRawRecord(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRawRecord", reflect.TypeOf((*MockListStorage)(nil).GetRawRecord), arg0, arg1) +} + +// Head mocks base method. +func (m *MockListStorage) Head() (*aclrecordproto.RawACLRecordWithId, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Head") + ret0, _ := ret[0].(*aclrecordproto.RawACLRecordWithId) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Head indicates an expected call of Head. +func (mr *MockListStorageMockRecorder) Head() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Head", reflect.TypeOf((*MockListStorage)(nil).Head)) +} + +// ID mocks base method. +func (m *MockListStorage) ID() (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ID") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ID indicates an expected call of ID. +func (mr *MockListStorageMockRecorder) ID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockListStorage)(nil).ID)) +} + +// Root mocks base method. +func (m *MockListStorage) Root() (*aclrecordproto.RawACLRecordWithId, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Root") + ret0, _ := ret[0].(*aclrecordproto.RawACLRecordWithId) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Root indicates an expected call of Root. +func (mr *MockListStorageMockRecorder) Root() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockListStorage)(nil).Root)) +} From beccba6d95bd23d55bad0585de20560c6a52279f Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Fri, 30 Sep 2022 14:43:11 +0200 Subject: [PATCH 06/17] Require no error in tests --- common/commonspace/diffservice/diffsyncer_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/commonspace/diffservice/diffsyncer_test.go b/common/commonspace/diffservice/diffsyncer_test.go index 64d0abfd..70a849d0 100644 --- a/common/commonspace/diffservice/diffsyncer_test.go +++ b/common/commonspace/diffservice/diffsyncer_test.go @@ -13,6 +13,7 @@ import ( storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff" "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" "storj.io/drpc" "testing" ) @@ -77,7 +78,7 @@ func TestDiffSyncer_Sync(t *testing.T) { GetTree(gomock.Any(), spaceId, arg). Return(cache.TreeResult{}, nil) } - _ = diffSyncer.Sync(ctx) + require.NoError(t, diffSyncer.Sync(ctx)) }) t.Run("diff syncer sync space missing", func(t *testing.T) { @@ -104,6 +105,6 @@ func TestDiffSyncer_Sync(t *testing.T) { PushSpace(gomock.Any(), newPushSpaceRequestMatcher(spaceId, aclRoot, spaceHeader)). Return(nil, nil) - _ = diffSyncer.Sync(ctx) + require.NoError(t, diffSyncer.Sync(ctx)) }) } From 86ef6d2dd6b256e7bf83c8aa792567d31e283930 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Fri, 30 Sep 2022 15:53:33 +0200 Subject: [PATCH 07/17] Move mocks to separate packages --- .../mock_cache.go} | 9 ++-- common/commonspace/cache/treecache.go | 2 +- .../diffservice/diffsyncer_test.go | 49 +++++++++++++++---- .../mock_spacesyncproto.go} | 17 ++++--- .../commonspace/spacesyncproto/spacesync.go | 2 +- .../mock_storage.go} | 13 ++--- common/commonspace/storage/storage.go | 2 +- common/nodeconf/configuration.go | 2 +- .../mock_nodeconf.go} | 4 +- pkg/acl/list/list.go | 2 +- .../{list_mock.go => mock_list/mock_list.go} | 25 +++++----- pkg/acl/storage/liststorage.go | 2 +- .../mock_storage.go} | 4 +- .../mock_objecttree.go} | 21 ++++---- pkg/acl/tree/objecttree.go | 2 +- pkg/ldiff/diff.go | 2 +- .../mock_ldiff.go} | 17 ++++--- 17 files changed, 105 insertions(+), 70 deletions(-) rename common/commonspace/cache/{treecache_mock.go => mock_cache/mock_cache.go} (93%) rename common/commonspace/spacesyncproto/{drpcspaceclient_mock.go => mock_spacesyncproto/mock_spacesyncproto.go} (82%) rename common/commonspace/storage/{storage_mock.go => mock_storage/mock_storage.go} (93%) rename common/nodeconf/{configuration_mock.go => mock_nodeconf/mock_nodeconf.go} (98%) rename pkg/acl/list/{list_mock.go => mock_list/mock_list.go} (90%) rename pkg/acl/storage/{liststorage_mock.go => mock_storage/mock_storage.go} (97%) rename pkg/acl/tree/{objecttree_mock.go => mock_objecttree/mock_objecttree.go} (93%) rename pkg/ldiff/{diff_mock.go => mock_ldiff/mock_ldiff.go} (85%) diff --git a/common/commonspace/cache/treecache_mock.go b/common/commonspace/cache/mock_cache/mock_cache.go similarity index 93% rename from common/commonspace/cache/treecache_mock.go rename to common/commonspace/cache/mock_cache/mock_cache.go index 1a42b411..84822cdb 100644 --- a/common/commonspace/cache/treecache_mock.go +++ b/common/commonspace/cache/mock_cache/mock_cache.go @@ -1,14 +1,15 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache (interfaces: TreeCache) -// Package cache is a generated GoMock package. -package cache +// Package mock_cache is a generated GoMock package. +package mock_cache import ( context "context" reflect "reflect" app "github.com/anytypeio/go-anytype-infrastructure-experiments/app" + cache "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" gomock "github.com/golang/mock/gomock" ) @@ -50,10 +51,10 @@ func (mr *MockTreeCacheMockRecorder) Close(arg0 interface{}) *gomock.Call { } // GetTree mocks base method. -func (m *MockTreeCache) GetTree(arg0 context.Context, arg1, arg2 string) (TreeResult, error) { +func (m *MockTreeCache) GetTree(arg0 context.Context, arg1, arg2 string) (cache.TreeResult, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetTree", arg0, arg1, arg2) - ret0, _ := ret[0].(TreeResult) + ret0, _ := ret[0].(cache.TreeResult) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/common/commonspace/cache/treecache.go b/common/commonspace/cache/treecache.go index 4f72f0fd..274f044a 100644 --- a/common/commonspace/cache/treecache.go +++ b/common/commonspace/cache/treecache.go @@ -1,4 +1,4 @@ -//go:generate mockgen -package cache -destination treecache_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache TreeCache +//go:generate mockgen -destination mock_cache/mock_cache.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache TreeCache package cache import ( diff --git a/common/commonspace/diffservice/diffsyncer_test.go b/common/commonspace/diffservice/diffsyncer_test.go index 70a849d0..211aecb7 100644 --- a/common/commonspace/diffservice/diffsyncer_test.go +++ b/common/commonspace/diffservice/diffsyncer_test.go @@ -4,14 +4,16 @@ import ( "context" "github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache/mock_cache" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" - "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto/mock_spacesyncproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer" - "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf/mock_nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto" - storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" - "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff" + mock_aclstorage "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage/mock_storage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff/mock_ldiff" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "storj.io/drpc" @@ -54,11 +56,11 @@ func TestDiffSyncer_Sync(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - diffMock := ldiff.NewMockDiff(ctrl) - nconfMock := nodeconf.NewMockConfiguration(ctrl) - cacheMock := cache.NewMockTreeCache(ctrl) - stMock := storage.NewMockSpaceStorage(ctrl) - clientMock := spacesyncproto.NewMockDRPCSpaceClient(ctrl) + diffMock := mock_ldiff.NewMockDiff(ctrl) + nconfMock := mock_nodeconf.NewMockConfiguration(ctrl) + cacheMock := mock_cache.NewMockTreeCache(ctrl) + stMock := mock_storage.NewMockSpaceStorage(ctrl) + clientMock := mock_spacesyncproto.NewMockDRPCSpaceClient(ctrl) factory := spacesyncproto.ClientFactoryFunc(func(cc drpc.Conn) spacesyncproto.DRPCSpaceClient { return clientMock }) @@ -82,7 +84,34 @@ func TestDiffSyncer_Sync(t *testing.T) { }) t.Run("diff syncer sync space missing", func(t *testing.T) { - aclStorageMock := storage2.NewMockListStorage(ctrl) + aclStorageMock := mock_aclstorage.NewMockListStorage(ctrl) + aclRoot := &aclrecordproto.RawACLRecordWithId{} + spaceHeader := &spacesyncproto.SpaceHeader{} + + nconfMock.EXPECT(). + ResponsiblePeers(gomock.Any(), spaceId). + Return([]peer.Peer{nil}, nil) + diffMock.EXPECT(). + Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))). + Return(nil, nil, nil, spacesyncproto.ErrSpaceMissing) + stMock.EXPECT(). + ACLStorage(). + Return(aclStorageMock, nil) + stMock.EXPECT(). + SpaceHeader(). + Return(spaceHeader, nil) + aclStorageMock.EXPECT(). + Root(). + Return(aclRoot, nil) + clientMock.EXPECT(). + PushSpace(gomock.Any(), newPushSpaceRequestMatcher(spaceId, aclRoot, spaceHeader)). + Return(nil, nil) + + require.NoError(t, diffSyncer.Sync(ctx)) + }) + + t.Run("diff syncer sync space missing", func(t *testing.T) { + aclStorageMock := mock_aclstorage.NewMockListStorage(ctrl) aclRoot := &aclrecordproto.RawACLRecordWithId{} spaceHeader := &spacesyncproto.SpaceHeader{} diff --git a/common/commonspace/spacesyncproto/drpcspaceclient_mock.go b/common/commonspace/spacesyncproto/mock_spacesyncproto/mock_spacesyncproto.go similarity index 82% rename from common/commonspace/spacesyncproto/drpcspaceclient_mock.go rename to common/commonspace/spacesyncproto/mock_spacesyncproto/mock_spacesyncproto.go index 4e8fd108..0d0d52c5 100644 --- a/common/commonspace/spacesyncproto/drpcspaceclient_mock.go +++ b/common/commonspace/spacesyncproto/mock_spacesyncproto/mock_spacesyncproto.go @@ -1,13 +1,14 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto (interfaces: DRPCSpaceClient) -// Package spacesyncproto is a generated GoMock package. -package spacesyncproto +// Package mock_spacesyncproto is a generated GoMock package. +package mock_spacesyncproto import ( context "context" reflect "reflect" + spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" gomock "github.com/golang/mock/gomock" drpc "storj.io/drpc" ) @@ -50,10 +51,10 @@ func (mr *MockDRPCSpaceClientMockRecorder) DRPCConn() *gomock.Call { } // HeadSync mocks base method. -func (m *MockDRPCSpaceClient) HeadSync(arg0 context.Context, arg1 *HeadSyncRequest) (*HeadSyncResponse, error) { +func (m *MockDRPCSpaceClient) HeadSync(arg0 context.Context, arg1 *spacesyncproto.HeadSyncRequest) (*spacesyncproto.HeadSyncResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "HeadSync", arg0, arg1) - ret0, _ := ret[0].(*HeadSyncResponse) + ret0, _ := ret[0].(*spacesyncproto.HeadSyncResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -65,10 +66,10 @@ func (mr *MockDRPCSpaceClientMockRecorder) HeadSync(arg0, arg1 interface{}) *gom } // PushSpace mocks base method. -func (m *MockDRPCSpaceClient) PushSpace(arg0 context.Context, arg1 *PushSpaceRequest) (*PushSpaceResponse, error) { +func (m *MockDRPCSpaceClient) PushSpace(arg0 context.Context, arg1 *spacesyncproto.PushSpaceRequest) (*spacesyncproto.PushSpaceResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PushSpace", arg0, arg1) - ret0, _ := ret[0].(*PushSpaceResponse) + ret0, _ := ret[0].(*spacesyncproto.PushSpaceResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -80,10 +81,10 @@ func (mr *MockDRPCSpaceClientMockRecorder) PushSpace(arg0, arg1 interface{}) *go } // Stream mocks base method. -func (m *MockDRPCSpaceClient) Stream(arg0 context.Context) (DRPCSpace_StreamClient, error) { +func (m *MockDRPCSpaceClient) Stream(arg0 context.Context) (spacesyncproto.DRPCSpace_StreamClient, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Stream", arg0) - ret0, _ := ret[0].(DRPCSpace_StreamClient) + ret0, _ := ret[0].(spacesyncproto.DRPCSpace_StreamClient) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/common/commonspace/spacesyncproto/spacesync.go b/common/commonspace/spacesyncproto/spacesync.go index e7924694..068642fe 100644 --- a/common/commonspace/spacesyncproto/spacesync.go +++ b/common/commonspace/spacesyncproto/spacesync.go @@ -1,4 +1,4 @@ -//go:generate mockgen -package spacesyncproto -destination drpcspaceclient_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto DRPCSpaceClient +//go:generate mockgen -destination mock_spacesyncproto/mock_spacesyncproto.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto DRPCSpaceClient package spacesyncproto import ( diff --git a/common/commonspace/storage/storage_mock.go b/common/commonspace/storage/mock_storage/mock_storage.go similarity index 93% rename from common/commonspace/storage/storage_mock.go rename to common/commonspace/storage/mock_storage/mock_storage.go index c671fbad..14b6003f 100644 --- a/common/commonspace/storage/storage_mock.go +++ b/common/commonspace/storage/mock_storage/mock_storage.go @@ -1,14 +1,15 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage (interfaces: SpaceStorageProvider,SpaceStorage) -// Package storage is a generated GoMock package. -package storage +// Package mock_storage is a generated GoMock package. +package mock_storage import ( reflect "reflect" app "github.com/anytypeio/go-anytype-infrastructure-experiments/app" spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" + storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" storage0 "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" gomock "github.com/golang/mock/gomock" ) @@ -37,10 +38,10 @@ func (m *MockSpaceStorageProvider) EXPECT() *MockSpaceStorageProviderMockRecorde } // CreateSpaceStorage mocks base method. -func (m *MockSpaceStorageProvider) CreateSpaceStorage(arg0 SpaceStorageCreatePayload) (SpaceStorage, error) { +func (m *MockSpaceStorageProvider) CreateSpaceStorage(arg0 storage.SpaceStorageCreatePayload) (storage.SpaceStorage, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CreateSpaceStorage", arg0) - ret0, _ := ret[0].(SpaceStorage) + ret0, _ := ret[0].(storage.SpaceStorage) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -80,10 +81,10 @@ func (mr *MockSpaceStorageProviderMockRecorder) Name() *gomock.Call { } // SpaceStorage mocks base method. -func (m *MockSpaceStorageProvider) SpaceStorage(arg0 string) (SpaceStorage, error) { +func (m *MockSpaceStorageProvider) SpaceStorage(arg0 string) (storage.SpaceStorage, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SpaceStorage", arg0) - ret0, _ := ret[0].(SpaceStorage) + ret0, _ := ret[0].(storage.SpaceStorage) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/common/commonspace/storage/storage.go b/common/commonspace/storage/storage.go index 60d852e6..fc1cfa8d 100644 --- a/common/commonspace/storage/storage.go +++ b/common/commonspace/storage/storage.go @@ -1,4 +1,4 @@ -//go:generate mockgen -package storage -destination storage_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage SpaceStorageProvider,SpaceStorage +//go:generate mockgen -destination mock_storage/mock_storage.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage SpaceStorageProvider,SpaceStorage package storage import ( diff --git a/common/nodeconf/configuration.go b/common/nodeconf/configuration.go index cb169103..8e50303b 100644 --- a/common/nodeconf/configuration.go +++ b/common/nodeconf/configuration.go @@ -1,4 +1,4 @@ -//go:generate mockgen -package nodeconf -destination configuration_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf Configuration +//go:generate mockgen -destination mock_nodeconf/mock_nodeconf.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf Configuration package nodeconf import ( diff --git a/common/nodeconf/configuration_mock.go b/common/nodeconf/mock_nodeconf/mock_nodeconf.go similarity index 98% rename from common/nodeconf/configuration_mock.go rename to common/nodeconf/mock_nodeconf/mock_nodeconf.go index c84e1848..e65895eb 100644 --- a/common/nodeconf/configuration_mock.go +++ b/common/nodeconf/mock_nodeconf/mock_nodeconf.go @@ -1,8 +1,8 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf (interfaces: Configuration) -// Package nodeconf is a generated GoMock package. -package nodeconf +// Package mock_nodeconf is a generated GoMock package. +package mock_nodeconf import ( context "context" diff --git a/pkg/acl/list/list.go b/pkg/acl/list/list.go index 0e2a31ed..dae887e6 100644 --- a/pkg/acl/list/list.go +++ b/pkg/acl/list/list.go @@ -1,4 +1,4 @@ -//go:generate mockgen -package list -destination list_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list ACLList +//go:generate mockgen -destination mock_list/mock_list.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list ACLList package list import ( diff --git a/pkg/acl/list/list_mock.go b/pkg/acl/list/mock_list/mock_list.go similarity index 90% rename from pkg/acl/list/list_mock.go rename to pkg/acl/list/mock_list/mock_list.go index 215ca59e..e4c7cc6e 100644 --- a/pkg/acl/list/list_mock.go +++ b/pkg/acl/list/mock_list/mock_list.go @@ -1,13 +1,14 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list (interfaces: ACLList) -// Package list is a generated GoMock package. -package list +// Package mock_list is a generated GoMock package. +package mock_list import ( reflect "reflect" aclrecordproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto" + list "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list" gomock "github.com/golang/mock/gomock" ) @@ -35,10 +36,10 @@ func (m *MockACLList) EXPECT() *MockACLListMockRecorder { } // ACLState mocks base method. -func (m *MockACLList) ACLState() *ACLState { +func (m *MockACLList) ACLState() *list.ACLState { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ACLState") - ret0, _ := ret[0].(*ACLState) + ret0, _ := ret[0].(*list.ACLState) return ret0 } @@ -63,10 +64,10 @@ func (mr *MockACLListMockRecorder) Close() *gomock.Call { } // Get mocks base method. -func (m *MockACLList) Get(arg0 string) (*ACLRecord, error) { +func (m *MockACLList) Get(arg0 string) (*list.ACLRecord, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Get", arg0) - ret0, _ := ret[0].(*ACLRecord) + ret0, _ := ret[0].(*list.ACLRecord) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -78,10 +79,10 @@ func (mr *MockACLListMockRecorder) Get(arg0 interface{}) *gomock.Call { } // Head mocks base method. -func (m *MockACLList) Head() *ACLRecord { +func (m *MockACLList) Head() *list.ACLRecord { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Head") - ret0, _ := ret[0].(*ACLRecord) + ret0, _ := ret[0].(*list.ACLRecord) return ret0 } @@ -121,7 +122,7 @@ func (mr *MockACLListMockRecorder) IsAfter(arg0, arg1 interface{}) *gomock.Call } // Iterate mocks base method. -func (m *MockACLList) Iterate(arg0 func(*ACLRecord) bool) { +func (m *MockACLList) Iterate(arg0 func(*list.ACLRecord) bool) { m.ctrl.T.Helper() m.ctrl.Call(m, "Iterate", arg0) } @@ -133,7 +134,7 @@ func (mr *MockACLListMockRecorder) Iterate(arg0 interface{}) *gomock.Call { } // IterateFrom mocks base method. -func (m *MockACLList) IterateFrom(arg0 string, arg1 func(*ACLRecord) bool) { +func (m *MockACLList) IterateFrom(arg0 string, arg1 func(*list.ACLRecord) bool) { m.ctrl.T.Helper() m.ctrl.Call(m, "IterateFrom", arg0, arg1) } @@ -181,10 +182,10 @@ func (mr *MockACLListMockRecorder) RUnlock() *gomock.Call { } // Records mocks base method. -func (m *MockACLList) Records() []*ACLRecord { +func (m *MockACLList) Records() []*list.ACLRecord { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Records") - ret0, _ := ret[0].([]*ACLRecord) + ret0, _ := ret[0].([]*list.ACLRecord) return ret0 } diff --git a/pkg/acl/storage/liststorage.go b/pkg/acl/storage/liststorage.go index 19b4dfe1..7aad8a01 100644 --- a/pkg/acl/storage/liststorage.go +++ b/pkg/acl/storage/liststorage.go @@ -1,4 +1,4 @@ -//go:generate mockgen -package storage -destination liststorage_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage ListStorage +//go:generate mockgen -destination mock_storage/mock_storage.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage ListStorage package storage import ( diff --git a/pkg/acl/storage/liststorage_mock.go b/pkg/acl/storage/mock_storage/mock_storage.go similarity index 97% rename from pkg/acl/storage/liststorage_mock.go rename to pkg/acl/storage/mock_storage/mock_storage.go index 07a5ef80..72dc884d 100644 --- a/pkg/acl/storage/liststorage_mock.go +++ b/pkg/acl/storage/mock_storage/mock_storage.go @@ -1,8 +1,8 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage (interfaces: ListStorage) -// Package storage is a generated GoMock package. -package storage +// Package mock_storage is a generated GoMock package. +package mock_storage import ( context "context" diff --git a/pkg/acl/tree/objecttree_mock.go b/pkg/acl/tree/mock_objecttree/mock_objecttree.go similarity index 93% rename from pkg/acl/tree/objecttree_mock.go rename to pkg/acl/tree/mock_objecttree/mock_objecttree.go index 5632850d..a4eac719 100644 --- a/pkg/acl/tree/objecttree_mock.go +++ b/pkg/acl/tree/mock_objecttree/mock_objecttree.go @@ -1,14 +1,15 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree (interfaces: ObjectTree) -// Package tree is a generated GoMock package. -package tree +// Package mock_tree is a generated GoMock package. +package mock_tree import ( context "context" reflect "reflect" storage "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" + tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree" treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" gomock "github.com/golang/mock/gomock" ) @@ -37,10 +38,10 @@ func (m *MockObjectTree) EXPECT() *MockObjectTreeMockRecorder { } // AddContent mocks base method. -func (m *MockObjectTree) AddContent(arg0 context.Context, arg1 SignableChangeContent) (AddResult, error) { +func (m *MockObjectTree) AddContent(arg0 context.Context, arg1 tree.SignableChangeContent) (tree.AddResult, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddContent", arg0, arg1) - ret0, _ := ret[0].(AddResult) + ret0, _ := ret[0].(tree.AddResult) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -52,14 +53,14 @@ func (mr *MockObjectTreeMockRecorder) AddContent(arg0, arg1 interface{}) *gomock } // AddRawChanges mocks base method. -func (m *MockObjectTree) AddRawChanges(arg0 context.Context, arg1 ...*treechangeproto.RawTreeChangeWithId) (AddResult, error) { +func (m *MockObjectTree) AddRawChanges(arg0 context.Context, arg1 ...*treechangeproto.RawTreeChangeWithId) (tree.AddResult, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0} for _, a := range arg1 { varargs = append(varargs, a) } ret := m.ctrl.Call(m, "AddRawChanges", varargs...) - ret0, _ := ret[0].(AddResult) + ret0, _ := ret[0].(tree.AddResult) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -172,7 +173,7 @@ func (mr *MockObjectTreeMockRecorder) ID() *gomock.Call { } // Iterate mocks base method. -func (m *MockObjectTree) Iterate(arg0 func([]byte) (interface{}, error), arg1 func(*Change) bool) error { +func (m *MockObjectTree) Iterate(arg0 func([]byte) (interface{}, error), arg1 func(*tree.Change) bool) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Iterate", arg0, arg1) ret0, _ := ret[0].(error) @@ -186,7 +187,7 @@ func (mr *MockObjectTreeMockRecorder) Iterate(arg0, arg1 interface{}) *gomock.Ca } // IterateFrom mocks base method. -func (m *MockObjectTree) IterateFrom(arg0 string, arg1 func([]byte) (interface{}, error), arg2 func(*Change) bool) error { +func (m *MockObjectTree) IterateFrom(arg0 string, arg1 func([]byte) (interface{}, error), arg2 func(*tree.Change) bool) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IterateFrom", arg0, arg1, arg2) ret0, _ := ret[0].(error) @@ -236,10 +237,10 @@ func (mr *MockObjectTreeMockRecorder) RUnlock() *gomock.Call { } // Root mocks base method. -func (m *MockObjectTree) Root() *Change { +func (m *MockObjectTree) Root() *tree.Change { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Root") - ret0, _ := ret[0].(*Change) + ret0, _ := ret[0].(*tree.Change) return ret0 } diff --git a/pkg/acl/tree/objecttree.go b/pkg/acl/tree/objecttree.go index 95348feb..47305d23 100644 --- a/pkg/acl/tree/objecttree.go +++ b/pkg/acl/tree/objecttree.go @@ -1,4 +1,4 @@ -//go:generate mockgen -package tree -destination objecttree_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree ObjectTree +//go:generate mockgen -destination mock_objecttree/mock_objecttree.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree ObjectTree package tree import ( diff --git a/pkg/ldiff/diff.go b/pkg/ldiff/diff.go index 10346e45..2f9a5161 100644 --- a/pkg/ldiff/diff.go +++ b/pkg/ldiff/diff.go @@ -1,4 +1,4 @@ -//go:generate mockgen -package ldiff -destination diff_mock.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff Diff,Remote +//go:generate mockgen -destination mock_ldiff/mock_ldiff.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff Diff,Remote // Package ldiff provides a container of elements with fixed id and changeable content. // Diff can calculate the difference with another diff container (you can make it remote) with minimum hops and traffic. package ldiff diff --git a/pkg/ldiff/diff_mock.go b/pkg/ldiff/mock_ldiff/mock_ldiff.go similarity index 85% rename from pkg/ldiff/diff_mock.go rename to pkg/ldiff/mock_ldiff/mock_ldiff.go index e750af44..183e7bef 100644 --- a/pkg/ldiff/diff_mock.go +++ b/pkg/ldiff/mock_ldiff/mock_ldiff.go @@ -1,13 +1,14 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff (interfaces: Diff,Remote) -// Package ldiff is a generated GoMock package. -package ldiff +// Package mock_ldiff is a generated GoMock package. +package mock_ldiff import ( context "context" reflect "reflect" + ldiff "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff" gomock "github.com/golang/mock/gomock" ) @@ -35,7 +36,7 @@ func (m *MockDiff) EXPECT() *MockDiffMockRecorder { } // Diff mocks base method. -func (m *MockDiff) Diff(arg0 context.Context, arg1 Remote) ([]string, []string, []string, error) { +func (m *MockDiff) Diff(arg0 context.Context, arg1 ldiff.Remote) ([]string, []string, []string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Diff", arg0, arg1) ret0, _ := ret[0].([]string) @@ -52,10 +53,10 @@ func (mr *MockDiffMockRecorder) Diff(arg0, arg1 interface{}) *gomock.Call { } // Ranges mocks base method. -func (m *MockDiff) Ranges(arg0 context.Context, arg1 []Range, arg2 []RangeResult) ([]RangeResult, error) { +func (m *MockDiff) Ranges(arg0 context.Context, arg1 []ldiff.Range, arg2 []ldiff.RangeResult) ([]ldiff.RangeResult, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Ranges", arg0, arg1, arg2) - ret0, _ := ret[0].([]RangeResult) + ret0, _ := ret[0].([]ldiff.RangeResult) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -81,7 +82,7 @@ func (mr *MockDiffMockRecorder) RemoveId(arg0 interface{}) *gomock.Call { } // Set mocks base method. -func (m *MockDiff) Set(arg0 ...Element) { +func (m *MockDiff) Set(arg0 ...ldiff.Element) { m.ctrl.T.Helper() varargs := []interface{}{} for _, a := range arg0 { @@ -120,10 +121,10 @@ func (m *MockRemote) EXPECT() *MockRemoteMockRecorder { } // Ranges mocks base method. -func (m *MockRemote) Ranges(arg0 context.Context, arg1 []Range, arg2 []RangeResult) ([]RangeResult, error) { +func (m *MockRemote) Ranges(arg0 context.Context, arg1 []ldiff.Range, arg2 []ldiff.RangeResult) ([]ldiff.RangeResult, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Ranges", arg0, arg1, arg2) - ret0, _ := ret[0].([]RangeResult) + ret0, _ := ret[0].([]ldiff.RangeResult) ret1, _ := ret[1].(error) return ret0, ret1 } From 53d10dc597ed953b5ea238db07e442dd31961f60 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Fri, 30 Sep 2022 16:02:47 +0200 Subject: [PATCH 08/17] Add more syncer tests --- .../diffservice/diffsyncer_test.go | 65 +++++++++++++------ 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/common/commonspace/diffservice/diffsyncer_test.go b/common/commonspace/diffservice/diffsyncer_test.go index 211aecb7..041857e3 100644 --- a/common/commonspace/diffservice/diffsyncer_test.go +++ b/common/commonspace/diffservice/diffsyncer_test.go @@ -2,6 +2,7 @@ package diffservice import ( "context" + "fmt" "github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache/mock_cache" @@ -18,6 +19,7 @@ import ( "github.com/stretchr/testify/require" "storj.io/drpc" "testing" + "time" ) type pushSpaceRequestMatcher struct { @@ -39,6 +41,35 @@ func (p pushSpaceRequestMatcher) String() string { return "" } +type mockPeer struct{} + +func (m mockPeer) Id() string { + return "mockId" +} + +func (m mockPeer) LastUsage() time.Time { + return time.Time{} +} + +func (m mockPeer) UpdateLastUsage() { +} + +func (m mockPeer) Close() error { + return nil +} + +func (m mockPeer) Closed() <-chan struct{} { + return make(chan struct{}) +} + +func (m mockPeer) Invoke(ctx context.Context, rpc string, enc drpc.Encoding, in, out drpc.Message) error { + return nil +} + +func (m mockPeer) NewStream(ctx context.Context, rpc string, enc drpc.Encoding) (drpc.Stream, error) { + return nil, nil +} + func newPushSpaceRequestMatcher( spaceId string, aclRoot *aclrecordproto.RawACLRecordWithId, @@ -71,7 +102,7 @@ func TestDiffSyncer_Sync(t *testing.T) { t.Run("diff syncer sync simple", func(t *testing.T) { nconfMock.EXPECT(). ResponsiblePeers(gomock.Any(), spaceId). - Return([]peer.Peer{nil}, nil) + Return([]peer.Peer{mockPeer{}}, nil) diffMock.EXPECT(). Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))). Return([]string{"new"}, []string{"changed"}, nil, nil) @@ -83,6 +114,14 @@ func TestDiffSyncer_Sync(t *testing.T) { require.NoError(t, diffSyncer.Sync(ctx)) }) + t.Run("diff syncer sync conf error", func(t *testing.T) { + nconfMock.EXPECT(). + ResponsiblePeers(gomock.Any(), spaceId). + Return(nil, fmt.Errorf("some error")) + + require.Error(t, diffSyncer.Sync(ctx)) + }) + t.Run("diff syncer sync space missing", func(t *testing.T) { aclStorageMock := mock_aclstorage.NewMockListStorage(ctrl) aclRoot := &aclrecordproto.RawACLRecordWithId{} @@ -90,7 +129,7 @@ func TestDiffSyncer_Sync(t *testing.T) { nconfMock.EXPECT(). ResponsiblePeers(gomock.Any(), spaceId). - Return([]peer.Peer{nil}, nil) + Return([]peer.Peer{mockPeer{}}, nil) diffMock.EXPECT(). Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))). Return(nil, nil, nil, spacesyncproto.ErrSpaceMissing) @@ -110,29 +149,13 @@ func TestDiffSyncer_Sync(t *testing.T) { require.NoError(t, diffSyncer.Sync(ctx)) }) - t.Run("diff syncer sync space missing", func(t *testing.T) { - aclStorageMock := mock_aclstorage.NewMockListStorage(ctrl) - aclRoot := &aclrecordproto.RawACLRecordWithId{} - spaceHeader := &spacesyncproto.SpaceHeader{} - + t.Run("diff syncer sync other error", func(t *testing.T) { nconfMock.EXPECT(). ResponsiblePeers(gomock.Any(), spaceId). - Return([]peer.Peer{nil}, nil) + Return([]peer.Peer{mockPeer{}}, nil) diffMock.EXPECT(). Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))). - Return(nil, nil, nil, spacesyncproto.ErrSpaceMissing) - stMock.EXPECT(). - ACLStorage(). - Return(aclStorageMock, nil) - stMock.EXPECT(). - SpaceHeader(). - Return(spaceHeader, nil) - aclStorageMock.EXPECT(). - Root(). - Return(aclRoot, nil) - clientMock.EXPECT(). - PushSpace(gomock.Any(), newPushSpaceRequestMatcher(spaceId, aclRoot, spaceHeader)). - Return(nil, nil) + Return(nil, nil, nil, spacesyncproto.ErrUnexpected) require.NoError(t, diffSyncer.Sync(ctx)) }) From aaaab9deca0f6bd1737ffa4d3d8ddca581010dbb Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Fri, 30 Sep 2022 16:12:41 +0200 Subject: [PATCH 09/17] Add periodicsync test --- common/commonspace/diffservice/diffservice.go | 1 + .../mock_diffservice/mock_diffservice.go | 49 +++++++++++++++++++ .../diffservice/periodicsync_test.go | 39 +++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 common/commonspace/diffservice/mock_diffservice/mock_diffservice.go create mode 100644 common/commonspace/diffservice/periodicsync_test.go diff --git a/common/commonspace/diffservice/diffservice.go b/common/commonspace/diffservice/diffservice.go index e5a94a1f..44401783 100644 --- a/common/commonspace/diffservice/diffservice.go +++ b/common/commonspace/diffservice/diffservice.go @@ -1,3 +1,4 @@ +//go:generate mockgen -destination mock_diffservice/mock_diffservice.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice DiffSyncer package diffservice import ( diff --git a/common/commonspace/diffservice/mock_diffservice/mock_diffservice.go b/common/commonspace/diffservice/mock_diffservice/mock_diffservice.go new file mode 100644 index 00000000..6f22a1a4 --- /dev/null +++ b/common/commonspace/diffservice/mock_diffservice/mock_diffservice.go @@ -0,0 +1,49 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice (interfaces: DiffSyncer) + +// Package mock_diffservice is a generated GoMock package. +package mock_diffservice + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockDiffSyncer is a mock of DiffSyncer interface. +type MockDiffSyncer struct { + ctrl *gomock.Controller + recorder *MockDiffSyncerMockRecorder +} + +// MockDiffSyncerMockRecorder is the mock recorder for MockDiffSyncer. +type MockDiffSyncerMockRecorder struct { + mock *MockDiffSyncer +} + +// NewMockDiffSyncer creates a new mock instance. +func NewMockDiffSyncer(ctrl *gomock.Controller) *MockDiffSyncer { + mock := &MockDiffSyncer{ctrl: ctrl} + mock.recorder = &MockDiffSyncerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDiffSyncer) EXPECT() *MockDiffSyncerMockRecorder { + return m.recorder +} + +// Sync mocks base method. +func (m *MockDiffSyncer) Sync(arg0 context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Sync", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Sync indicates an expected call of Sync. +func (mr *MockDiffSyncerMockRecorder) Sync(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sync", reflect.TypeOf((*MockDiffSyncer)(nil).Sync), arg0) +} diff --git a/common/commonspace/diffservice/periodicsync_test.go b/common/commonspace/diffservice/periodicsync_test.go new file mode 100644 index 00000000..5b7c7e41 --- /dev/null +++ b/common/commonspace/diffservice/periodicsync_test.go @@ -0,0 +1,39 @@ +package diffservice + +import ( + "github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice/mock_diffservice" + "github.com/golang/mock/gomock" + "testing" + "time" +) + +func TestPeriodicSync_Run(t *testing.T) { + // setup + //ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + l := logger.NewNamed("sync") + diffSyncer := mock_diffservice.NewMockDiffSyncer(ctrl) + t.Run("diff syncer 1 time", func(t *testing.T) { + secs := 0 + pSync := newPeriodicSync(secs, diffSyncer, l) + + diffSyncer.EXPECT().Sync(gomock.Any()).Times(1).Return(nil) + + pSync.Run() + pSync.Close() + }) + + t.Run("diff syncer 2 times", func(t *testing.T) { + secs := 1 + + pSync := newPeriodicSync(secs, diffSyncer, l) + diffSyncer.EXPECT().Sync(gomock.Any()).Times(2).Return(nil) + + pSync.Run() + time.Sleep(time.Second * time.Duration(secs)) + pSync.Close() + }) +} From 48ae45550d191325c0dd9905b67867f77ff89ff5 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Fri, 30 Sep 2022 16:55:34 +0200 Subject: [PATCH 10/17] Add diffservice tests --- common/commonspace/diffservice/diffservice.go | 2 +- .../diffservice/diffservice_test.go | 59 +++++++++ .../mock_diffservice/mock_diffservice.go | 49 +++++++- .../diffservice/periodicsync_test.go | 1 - pkg/acl/storage/liststorage.go | 2 +- pkg/acl/storage/mock_storage/mock_storage.go | 114 +++++++++++++++++- 6 files changed, 222 insertions(+), 5 deletions(-) create mode 100644 common/commonspace/diffservice/diffservice_test.go diff --git a/common/commonspace/diffservice/diffservice.go b/common/commonspace/diffservice/diffservice.go index 44401783..15a9ff65 100644 --- a/common/commonspace/diffservice/diffservice.go +++ b/common/commonspace/diffservice/diffservice.go @@ -1,4 +1,4 @@ -//go:generate mockgen -destination mock_diffservice/mock_diffservice.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice DiffSyncer +//go:generate mockgen -destination mock_diffservice/mock_diffservice.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice DiffSyncer,PeriodicSync package diffservice import ( diff --git a/common/commonspace/diffservice/diffservice_test.go b/common/commonspace/diffservice/diffservice_test.go new file mode 100644 index 00000000..27b4da3b --- /dev/null +++ b/common/commonspace/diffservice/diffservice_test.go @@ -0,0 +1,59 @@ +package diffservice + +import ( + "github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice/mock_diffservice" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage" + mock_storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage/mock_storage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff/mock_ldiff" + "github.com/golang/mock/gomock" + "testing" +) + +func TestDiffService(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + spaceId := "spaceId" + l := logger.NewNamed("sync") + pSyncMock := mock_diffservice.NewMockPeriodicSync(ctrl) + storageMock := mock_storage.NewMockSpaceStorage(ctrl) + treeStorageMock := mock_storage2.NewMockTreeStorage(ctrl) + diffMock := mock_ldiff.NewMockDiff(ctrl) + syncPeriod := 1 + initId := "initId" + + service := &diffService{ + spaceId: spaceId, + storage: storageMock, + periodicSync: pSyncMock, + diff: diffMock, + log: l, + syncPeriod: syncPeriod, + } + + t.Run("init", func(t *testing.T) { + storageMock.EXPECT().TreeStorage(initId).Return(treeStorageMock, nil) + treeStorageMock.EXPECT().Heads().Return([]string{"h1", "h2"}, nil) + diffMock.EXPECT().Set(ldiff.Element{ + Id: initId, + Head: "h1h2", + }) + pSyncMock.EXPECT().Run() + service.Init([]string{initId}) + }) + + t.Run("update heads", func(t *testing.T) { + diffMock.EXPECT().Set(ldiff.Element{ + Id: initId, + Head: "h1h2", + }) + service.UpdateHeads(initId, []string{"h1", "h2"}) + }) + + t.Run("close", func(t *testing.T) { + pSyncMock.EXPECT().Close() + service.Close() + }) +} diff --git a/common/commonspace/diffservice/mock_diffservice/mock_diffservice.go b/common/commonspace/diffservice/mock_diffservice/mock_diffservice.go index 6f22a1a4..966a7cc5 100644 --- a/common/commonspace/diffservice/mock_diffservice/mock_diffservice.go +++ b/common/commonspace/diffservice/mock_diffservice/mock_diffservice.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice (interfaces: DiffSyncer) +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice (interfaces: DiffSyncer,PeriodicSync) // Package mock_diffservice is a generated GoMock package. package mock_diffservice @@ -47,3 +47,50 @@ func (mr *MockDiffSyncerMockRecorder) Sync(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sync", reflect.TypeOf((*MockDiffSyncer)(nil).Sync), arg0) } + +// MockPeriodicSync is a mock of PeriodicSync interface. +type MockPeriodicSync struct { + ctrl *gomock.Controller + recorder *MockPeriodicSyncMockRecorder +} + +// MockPeriodicSyncMockRecorder is the mock recorder for MockPeriodicSync. +type MockPeriodicSyncMockRecorder struct { + mock *MockPeriodicSync +} + +// NewMockPeriodicSync creates a new mock instance. +func NewMockPeriodicSync(ctrl *gomock.Controller) *MockPeriodicSync { + mock := &MockPeriodicSync{ctrl: ctrl} + mock.recorder = &MockPeriodicSyncMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockPeriodicSync) EXPECT() *MockPeriodicSyncMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockPeriodicSync) Close() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Close") +} + +// Close indicates an expected call of Close. +func (mr *MockPeriodicSyncMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPeriodicSync)(nil).Close)) +} + +// Run mocks base method. +func (m *MockPeriodicSync) Run() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Run") +} + +// Run indicates an expected call of Run. +func (mr *MockPeriodicSyncMockRecorder) Run() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockPeriodicSync)(nil).Run)) +} diff --git a/common/commonspace/diffservice/periodicsync_test.go b/common/commonspace/diffservice/periodicsync_test.go index 5b7c7e41..56d855f2 100644 --- a/common/commonspace/diffservice/periodicsync_test.go +++ b/common/commonspace/diffservice/periodicsync_test.go @@ -10,7 +10,6 @@ import ( func TestPeriodicSync_Run(t *testing.T) { // setup - //ctx := context.Background() ctrl := gomock.NewController(t) defer ctrl.Finish() diff --git a/pkg/acl/storage/liststorage.go b/pkg/acl/storage/liststorage.go index 7aad8a01..222fd8d8 100644 --- a/pkg/acl/storage/liststorage.go +++ b/pkg/acl/storage/liststorage.go @@ -1,4 +1,4 @@ -//go:generate mockgen -destination mock_storage/mock_storage.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage ListStorage +//go:generate mockgen -destination mock_storage/mock_storage.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage ListStorage,TreeStorage package storage import ( diff --git a/pkg/acl/storage/mock_storage/mock_storage.go b/pkg/acl/storage/mock_storage/mock_storage.go index 72dc884d..5fff6944 100644 --- a/pkg/acl/storage/mock_storage/mock_storage.go +++ b/pkg/acl/storage/mock_storage/mock_storage.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage (interfaces: ListStorage) +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage (interfaces: ListStorage,TreeStorage) // Package mock_storage is a generated GoMock package. package mock_storage @@ -9,6 +9,7 @@ import ( reflect "reflect" aclrecordproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto" + treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" gomock "github.com/golang/mock/gomock" ) @@ -108,3 +109,114 @@ func (mr *MockListStorageMockRecorder) Root() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockListStorage)(nil).Root)) } + +// MockTreeStorage is a mock of TreeStorage interface. +type MockTreeStorage struct { + ctrl *gomock.Controller + recorder *MockTreeStorageMockRecorder +} + +// MockTreeStorageMockRecorder is the mock recorder for MockTreeStorage. +type MockTreeStorageMockRecorder struct { + mock *MockTreeStorage +} + +// NewMockTreeStorage creates a new mock instance. +func NewMockTreeStorage(ctrl *gomock.Controller) *MockTreeStorage { + mock := &MockTreeStorage{ctrl: ctrl} + mock.recorder = &MockTreeStorageMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockTreeStorage) EXPECT() *MockTreeStorageMockRecorder { + return m.recorder +} + +// AddRawChange mocks base method. +func (m *MockTreeStorage) AddRawChange(arg0 *treechangeproto.RawTreeChangeWithId) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddRawChange", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddRawChange indicates an expected call of AddRawChange. +func (mr *MockTreeStorageMockRecorder) AddRawChange(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChange", reflect.TypeOf((*MockTreeStorage)(nil).AddRawChange), arg0) +} + +// GetRawChange mocks base method. +func (m *MockTreeStorage) GetRawChange(arg0 context.Context, arg1 string) (*treechangeproto.RawTreeChangeWithId, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRawChange", arg0, arg1) + ret0, _ := ret[0].(*treechangeproto.RawTreeChangeWithId) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetRawChange indicates an expected call of GetRawChange. +func (mr *MockTreeStorageMockRecorder) GetRawChange(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRawChange", reflect.TypeOf((*MockTreeStorage)(nil).GetRawChange), arg0, arg1) +} + +// Heads mocks base method. +func (m *MockTreeStorage) Heads() ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Heads") + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Heads indicates an expected call of Heads. +func (mr *MockTreeStorageMockRecorder) Heads() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Heads", reflect.TypeOf((*MockTreeStorage)(nil).Heads)) +} + +// ID mocks base method. +func (m *MockTreeStorage) ID() (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ID") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ID indicates an expected call of ID. +func (mr *MockTreeStorageMockRecorder) ID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockTreeStorage)(nil).ID)) +} + +// Root mocks base method. +func (m *MockTreeStorage) Root() (*treechangeproto.RawTreeChangeWithId, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Root") + ret0, _ := ret[0].(*treechangeproto.RawTreeChangeWithId) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Root indicates an expected call of Root. +func (mr *MockTreeStorageMockRecorder) Root() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockTreeStorage)(nil).Root)) +} + +// SetHeads mocks base method. +func (m *MockTreeStorage) SetHeads(arg0 []string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetHeads", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetHeads indicates an expected call of SetHeads. +func (mr *MockTreeStorageMockRecorder) SetHeads(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHeads", reflect.TypeOf((*MockTreeStorage)(nil).SetHeads), arg0) +} From edc9a14ef5b6d32f6e467803e68cb26a71ad203c Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Sat, 1 Oct 2022 21:04:31 +0200 Subject: [PATCH 11/17] Few tree sync fixes and additions --- .../mock_syncservice/mock_syncservice.go | 78 ++++++ common/commonspace/syncservice/synchandler.go | 27 +- .../syncservice/synchandler_test.go | 58 +++++ pkg/acl/storage/inmemory.go | 5 + pkg/acl/storage/mock_storage/mock_storage.go | 15 ++ pkg/acl/storage/treestorage.go | 1 + .../tree/mock_objecttree/mock_objecttree.go | 16 +- pkg/acl/tree/objecttree.go | 236 +++++++++++------- pkg/acl/tree/objecttreefactory.go | 2 +- 9 files changed, 325 insertions(+), 113 deletions(-) create mode 100644 common/commonspace/syncservice/mock_syncservice/mock_syncservice.go create mode 100644 common/commonspace/syncservice/synchandler_test.go diff --git a/common/commonspace/syncservice/mock_syncservice/mock_syncservice.go b/common/commonspace/syncservice/mock_syncservice/mock_syncservice.go new file mode 100644 index 00000000..8438ab64 --- /dev/null +++ b/common/commonspace/syncservice/mock_syncservice/mock_syncservice.go @@ -0,0 +1,78 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice (interfaces: SyncClient) + +// Package mock_syncservice is a generated GoMock package. +package mock_syncservice + +import ( + reflect "reflect" + + spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" + gomock "github.com/golang/mock/gomock" +) + +// MockSyncClient is a mock of SyncClient interface. +type MockSyncClient struct { + ctrl *gomock.Controller + recorder *MockSyncClientMockRecorder +} + +// MockSyncClientMockRecorder is the mock recorder for MockSyncClient. +type MockSyncClientMockRecorder struct { + mock *MockSyncClient +} + +// NewMockSyncClient creates a new mock instance. +func NewMockSyncClient(ctrl *gomock.Controller) *MockSyncClient { + mock := &MockSyncClient{ctrl: ctrl} + mock.recorder = &MockSyncClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockSyncClient) EXPECT() *MockSyncClientMockRecorder { + return m.recorder +} + +// BroadcastAsync mocks base method. +func (m *MockSyncClient) BroadcastAsync(arg0 *spacesyncproto.ObjectSyncMessage) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BroadcastAsync", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// BroadcastAsync indicates an expected call of BroadcastAsync. +func (mr *MockSyncClientMockRecorder) BroadcastAsync(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastAsync", reflect.TypeOf((*MockSyncClient)(nil).BroadcastAsync), arg0) +} + +// SendAsync mocks base method. +func (m *MockSyncClient) SendAsync(arg0 string, arg1 *spacesyncproto.ObjectSyncMessage) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendAsync", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendAsync indicates an expected call of SendAsync. +func (mr *MockSyncClientMockRecorder) SendAsync(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendAsync", reflect.TypeOf((*MockSyncClient)(nil).SendAsync), arg0, arg1) +} + +// SendSync mocks base method. +func (m *MockSyncClient) SendSync(arg0 string, arg1 *spacesyncproto.ObjectSyncMessage) (*spacesyncproto.ObjectSyncMessage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendSync", arg0, arg1) + ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SendSync indicates an expected call of SendSync. +func (mr *MockSyncClientMockRecorder) SendSync(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendSync", reflect.TypeOf((*MockSyncClient)(nil).SendSync), arg0, arg1) +} diff --git a/common/commonspace/syncservice/synchandler.go b/common/commonspace/syncservice/synchandler.go index 3a0da9fd..0123cbff 100644 --- a/common/commonspace/syncservice/synchandler.go +++ b/common/commonspace/syncservice/synchandler.go @@ -1,3 +1,4 @@ +//go:generate mockgen -destination mock_syncservice/mock_syncservice.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice SyncClient package syncservice import ( @@ -31,16 +32,16 @@ func (s *syncHandler) HandleMessage(ctx context.Context, senderId string, msg *s content := msg.GetContent() switch { case content.GetFullSyncRequest() != nil: - return s.HandleFullSyncRequest(ctx, senderId, content.GetFullSyncRequest(), msg) + return s.handleFullSyncRequest(ctx, senderId, content.GetFullSyncRequest(), msg) case content.GetFullSyncResponse() != nil: - return s.HandleFullSyncResponse(ctx, senderId, content.GetFullSyncResponse(), msg) + return s.handleFullSyncResponse(ctx, senderId, content.GetFullSyncResponse(), msg) case content.GetHeadUpdate() != nil: - return s.HandleHeadUpdate(ctx, senderId, content.GetHeadUpdate(), msg) + return s.handleHeadUpdate(ctx, senderId, content.GetHeadUpdate(), msg) } return nil } -func (s *syncHandler) HandleHeadUpdate( +func (s *syncHandler) handleHeadUpdate( ctx context.Context, senderId string, update *spacesyncproto.ObjectHeadUpdate, @@ -70,12 +71,14 @@ func (s *syncHandler) HandleHeadUpdate( return err } - // if we couldn't add all the changes - if len(update.Changes) != len(result.Added) { - fullRequest, err = s.prepareFullSyncRequest(objTree, update) - if err != nil { - return err - } + // if after the heads are equal, or we have them locally + if slice.UnsortedEquals(update.Heads, result.Heads) || objTree.HasChanges(update.Heads...) { + return nil + } + + fullRequest, err = s.prepareFullSyncRequest(objTree, update) + if err != nil { + return err } return nil }() @@ -87,7 +90,7 @@ func (s *syncHandler) HandleHeadUpdate( return } -func (s *syncHandler) HandleFullSyncRequest( +func (s *syncHandler) handleFullSyncRequest( ctx context.Context, senderId string, request *spacesyncproto.ObjectFullSyncRequest, @@ -133,7 +136,7 @@ func (s *syncHandler) HandleFullSyncRequest( spacesyncproto.WrapFullResponse(fullResponse, header, msg.TreeId, msg.TrackingId)) } -func (s *syncHandler) HandleFullSyncResponse( +func (s *syncHandler) handleFullSyncResponse( ctx context.Context, senderId string, response *spacesyncproto.ObjectFullSyncResponse, diff --git a/common/commonspace/syncservice/synchandler_test.go b/common/commonspace/syncservice/synchandler_test.go new file mode 100644 index 00000000..dc145017 --- /dev/null +++ b/common/commonspace/syncservice/synchandler_test.go @@ -0,0 +1,58 @@ +package syncservice + +import ( + "context" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache/mock_cache" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/mock_syncservice" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree" + mock_tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree/mock_objecttree" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + "testing" +) + +type treeContainer struct { + objTree tree.ObjectTree +} + +func (t treeContainer) Tree() tree.ObjectTree { + return t.objTree +} + +func TestSyncHandler_HandleMessage(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + ctx := context.Background() + spaceId := "spaceId" + cacheMock := mock_cache.NewMockTreeCache(ctrl) + syncClientMock := mock_syncservice.NewMockSyncClient(ctrl) + 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) +} diff --git a/pkg/acl/storage/inmemory.go b/pkg/acl/storage/inmemory.go index 6ddbea57..487caa04 100644 --- a/pkg/acl/storage/inmemory.go +++ b/pkg/acl/storage/inmemory.go @@ -87,6 +87,11 @@ func NewInMemoryTreeStorage( }, nil } +func (t *inMemoryTreeStorage) HasChange(ctx context.Context, id string) (bool, error) { + _, exists := t.changes[id] + return exists, nil +} + func (t *inMemoryTreeStorage) ID() (string, error) { t.RLock() defer t.RUnlock() diff --git a/pkg/acl/storage/mock_storage/mock_storage.go b/pkg/acl/storage/mock_storage/mock_storage.go index 5fff6944..f20bf468 100644 --- a/pkg/acl/storage/mock_storage/mock_storage.go +++ b/pkg/acl/storage/mock_storage/mock_storage.go @@ -162,6 +162,21 @@ func (mr *MockTreeStorageMockRecorder) GetRawChange(arg0, arg1 interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRawChange", reflect.TypeOf((*MockTreeStorage)(nil).GetRawChange), arg0, arg1) } +// HasChange mocks base method. +func (m *MockTreeStorage) HasChange(arg0 context.Context, arg1 string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasChange", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// HasChange indicates an expected call of HasChange. +func (mr *MockTreeStorageMockRecorder) HasChange(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasChange", reflect.TypeOf((*MockTreeStorage)(nil).HasChange), arg0, arg1) +} + // Heads mocks base method. func (m *MockTreeStorage) Heads() ([]string, error) { m.ctrl.T.Helper() diff --git a/pkg/acl/storage/treestorage.go b/pkg/acl/storage/treestorage.go index a9c98f1d..25b91e46 100644 --- a/pkg/acl/storage/treestorage.go +++ b/pkg/acl/storage/treestorage.go @@ -13,6 +13,7 @@ type TreeStorage interface { AddRawChange(change *treechangeproto.RawTreeChangeWithId) error GetRawChange(ctx context.Context, id string) (*treechangeproto.RawTreeChangeWithId, error) + HasChange(ctx context.Context, id string) (bool, error) } type TreeStorageCreatorFunc = func(payload TreeStorageCreatePayload) (TreeStorage, error) diff --git a/pkg/acl/tree/mock_objecttree/mock_objecttree.go b/pkg/acl/tree/mock_objecttree/mock_objecttree.go index a4eac719..70afa9d4 100644 --- a/pkg/acl/tree/mock_objecttree/mock_objecttree.go +++ b/pkg/acl/tree/mock_objecttree/mock_objecttree.go @@ -116,18 +116,22 @@ func (mr *MockObjectTreeMockRecorder) DebugDump() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DebugDump", reflect.TypeOf((*MockObjectTree)(nil).DebugDump)) } -// HasChange mocks base method. -func (m *MockObjectTree) HasChange(arg0 string) bool { +// HasChanges mocks base method. +func (m *MockObjectTree) HasChanges(arg0 ...string) bool { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HasChange", arg0) + varargs := []interface{}{} + for _, a := range arg0 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HasChanges", varargs...) ret0, _ := ret[0].(bool) return ret0 } -// HasChange indicates an expected call of HasChange. -func (mr *MockObjectTreeMockRecorder) HasChange(arg0 interface{}) *gomock.Call { +// HasChanges indicates an expected call of HasChanges. +func (mr *MockObjectTreeMockRecorder) HasChanges(arg0 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasChange", reflect.TypeOf((*MockObjectTree)(nil).HasChange), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasChanges", reflect.TypeOf((*MockObjectTree)(nil).HasChanges), arg0...) } // Header mocks base method. diff --git a/pkg/acl/tree/objecttree.go b/pkg/acl/tree/objecttree.go index 47305d23..9e6323aa 100644 --- a/pkg/acl/tree/objecttree.go +++ b/pkg/acl/tree/objecttree.go @@ -43,7 +43,7 @@ type ObjectTree interface { Header() *treechangeproto.RawTreeChangeWithId Heads() []string Root() *Change - HasChange(string) bool + HasChanges(...string) bool DebugDump() (string, error) Iterate(convert ChangeConvertFunc, iterate ChangeIterateFunc) error @@ -76,7 +76,7 @@ type objectTree struct { // buffers difSnapshotBuf []*treechangeproto.RawTreeChangeWithId - tmpChangesBuf []*Change + newChangesBuf []*Change newSnapshotsBuf []*Change notSeenIdxBuf []int @@ -227,7 +227,7 @@ func (ot *objectTree) AddRawChanges(ctx context.Context, rawChanges ...*treechan func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechangeproto.RawTreeChangeWithId) (addResult AddResult, err error) { // resetting buffers - ot.tmpChangesBuf = ot.tmpChangesBuf[:0] + ot.newChangesBuf = ot.newChangesBuf[:0] ot.notSeenIdxBuf = ot.notSeenIdxBuf[:0] ot.difSnapshotBuf = ot.difSnapshotBuf[:0] ot.newSnapshotsBuf = ot.newSnapshotsBuf[:0] @@ -247,20 +247,21 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechan if _, exists := ot.tree.attached[ch.Id]; exists { continue } - if _, exists := ot.tree.unAttached[ch.Id]; exists { - continue - } var change *Change - change, err = ot.changeBuilder.ConvertFromRaw(ch, true) - if err != nil { - return + if unAttached, exists := ot.tree.unAttached[ch.Id]; exists { + change = unAttached + } else { + change, err = ot.changeBuilder.ConvertFromRaw(ch, true) + if err != nil { + return + } } if change.IsSnapshot { ot.newSnapshotsBuf = append(ot.newSnapshotsBuf, change) } - ot.tmpChangesBuf = append(ot.tmpChangesBuf, change) + ot.newChangesBuf = append(ot.newChangesBuf, change) ot.notSeenIdxBuf = append(ot.notSeenIdxBuf, idx) } @@ -274,6 +275,106 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechan return } + rollback := func(changes []*Change) { + for _, ch := range changes { + if _, exists := ot.tree.attached[ch.Id]; exists { + delete(ot.tree.attached, ch.Id) + } + } + } + + // checks if we need to go to database + isOldSnapshot := func(ch *Change) bool { + if ch.SnapshotId == ot.tree.RootId() { + return false + } + for _, sn := range ot.newSnapshotsBuf { + // if change refers to newly received snapshot + if ch.SnapshotId == sn.Id { + return false + } + } + return true + } + + shouldRebuildFromStorage := false + // checking if we have some changes with different snapshot and then rebuilding + for idx, ch := range ot.newChangesBuf { + if isOldSnapshot(ch) { + var exists bool + // checking if it exists in the storage, if yes, then at some point it was added to the tree + // thus we don't need to look at this change + exists, err = ot.treeStorage.HasChange(ctx, ch.Id) + if err != nil { + return + } + if exists { + // marking as nil to delete after + ot.newChangesBuf[idx] = nil + continue + } + // we haven't seen the change, and it refers to old snapshot, so we should rebuild + shouldRebuildFromStorage = true + } + } + // discarding all previously seen changes + ot.newChangesBuf = discardFromSlice(ot.newChangesBuf, func(ch *Change) bool { return ch == nil }) + + if shouldRebuildFromStorage { + err = ot.rebuildFromStorage(ot.newChangesBuf) + if err != nil { + // rebuilding without new changes + ot.rebuildFromStorage(nil) + return + } + addResult, err = ot.createAddResult(prevHeadsCopy, Rebuild, nil, rawChanges) + if err != nil { + // that means that some unattached changes were somehow corrupted in memory + // this shouldn't happen but if that happens, then rebuilding from storage + ot.rebuildFromStorage(nil) + return + } + return + } + + // normal mode of operation, where we don't need to rebuild from database + mode, treeChangesAdded := ot.tree.Add(ot.newChangesBuf...) + switch mode { + case Nothing: + addResult = AddResult{ + OldHeads: prevHeadsCopy, + Heads: prevHeadsCopy, + Mode: mode, + } + return + + default: + // we need to validate only newly added changes + err = ot.validateTree(treeChangesAdded) + if err != nil { + rollback(treeChangesAdded) + err = ErrHasInvalidChanges + return + } + addResult, err = ot.createAddResult(prevHeadsCopy, mode, treeChangesAdded, rawChanges) + if err != nil { + // that means that some unattached changes were somehow corrupted in memory + // this shouldn't happen but if that happens, then rebuilding from storage + ot.rebuildFromStorage(nil) + return + } + return + } + return +} + +func (ot *objectTree) createAddResult(oldHeads []string, mode Mode, treeChangesAdded []*Change, rawChanges []*treechangeproto.RawTreeChangeWithId) (addResult AddResult, err error) { + headsCopy := func() []string { + newHeads := make([]string, 0, len(ot.tree.Heads())) + newHeads = append(newHeads, ot.tree.Heads()...) + return newHeads + } + // returns changes that we added to the tree as attached this round // they can include not only the changes that were added now, // but also the changes that were previously in the tree @@ -313,88 +414,16 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechan return } - rollback := func(changes []*Change) { - for _, ch := range changes { - if _, exists := ot.tree.attached[ch.Id]; exists { - delete(ot.tree.attached, ch.Id) - } - } - } - - // checks if we need to go to database - isOldSnapshot := func(ch *Change) bool { - if ch.SnapshotId == ot.tree.RootId() { - return false - } - for _, sn := range ot.newSnapshotsBuf { - // if change refers to newly received snapshot - if ch.SnapshotId == sn.Id { - return false - } - } - return true - } - - // checking if we have some changes with different snapshot and then rebuilding - for _, ch := range ot.tmpChangesBuf { - if isOldSnapshot(ch) { - err = ot.rebuildFromStorage(ot.tmpChangesBuf) - if err != nil { - // rebuilding without new changes - ot.rebuildFromStorage(nil) - return - } - var added []*treechangeproto.RawTreeChangeWithId - added, err = getAddedChanges(nil) - // we shouldn't get any error in this case - if err != nil { - panic(err) - } - - addResult = AddResult{ - OldHeads: prevHeadsCopy, - Heads: headsCopy(), - Added: added, - Mode: Rebuild, - } - return - } - } - - // normal mode of operation, where we don't need to rebuild from database - mode, treeChangesAdded := ot.tree.Add(ot.tmpChangesBuf...) - switch mode { - case Nothing: - addResult = AddResult{ - OldHeads: prevHeadsCopy, - Heads: prevHeadsCopy, - Mode: mode, - } + var added []*treechangeproto.RawTreeChangeWithId + added, err = getAddedChanges(treeChangesAdded) + if err != nil { return - - default: - // we need to validate only newly added changes - err = ot.validateTree(treeChangesAdded) - if err != nil { - rollback(treeChangesAdded) - err = ErrHasInvalidChanges - return - } - var added []*treechangeproto.RawTreeChangeWithId - added, err = getAddedChanges(treeChangesAdded) - if err != nil { - // that means that some unattached changes were somehow corrupted in memory - // this shouldn't happen but if that happens, then rebuilding from storage - ot.rebuildFromStorage(nil) - return - } - - addResult = AddResult{ - OldHeads: prevHeadsCopy, - Heads: headsCopy(), - Added: added, - Mode: mode, - } + } + addResult = AddResult{ + OldHeads: oldHeads, + Heads: headsCopy(), + Added: added, + Mode: mode, } return } @@ -441,9 +470,28 @@ func (ot *objectTree) IterateFrom(id string, convert ChangeConvertFunc, iterate return } -func (ot *objectTree) HasChange(s string) bool { - _, attachedExists := ot.tree.attached[s] - return attachedExists +func (ot *objectTree) HasChanges(chs ...string) bool { + hasChange := func(s string) bool { + _, attachedExists := ot.tree.attached[s] + if attachedExists { + return attachedExists + } + + has, err := ot.treeStorage.HasChange(context.Background(), s) + if err != nil { + return false + } + + return has + } + + for _, ch := range chs { + if !hasChange(ch) { + return false + } + } + + return true } func (ot *objectTree) Heads() []string { diff --git a/pkg/acl/tree/objecttreefactory.go b/pkg/acl/tree/objecttreefactory.go index 61631412..1db77908 100644 --- a/pkg/acl/tree/objecttreefactory.go +++ b/pkg/acl/tree/objecttreefactory.go @@ -104,7 +104,7 @@ func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) { rawChangeLoader: deps.rawChangeLoader, tree: nil, keys: make(map[uint64]*symmetric.Key), - tmpChangesBuf: make([]*Change, 0, 10), + newChangesBuf: make([]*Change, 0, 10), difSnapshotBuf: make([]*treechangeproto.RawTreeChangeWithId, 0, 10), notSeenIdxBuf: make([]int, 0, 10), newSnapshotsBuf: make([]*Change, 0, 10), From 20234269e9d3ca0595244627dede932be05751da Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Sun, 2 Oct 2022 11:54:34 +0200 Subject: [PATCH 12/17] Update sync handler --- .../commonspace/syncservice/requestfactory.go | 59 ++++++++++++++ common/commonspace/syncservice/synchandler.go | 77 +++++-------------- common/commonspace/syncservice/syncservice.go | 2 +- 3 files changed, 80 insertions(+), 58 deletions(-) create mode 100644 common/commonspace/syncservice/requestfactory.go diff --git a/common/commonspace/syncservice/requestfactory.go b/common/commonspace/syncservice/requestfactory.go new file mode 100644 index 00000000..ab19bc6a --- /dev/null +++ b/common/commonspace/syncservice/requestfactory.go @@ -0,0 +1,59 @@ +package syncservice + +import ( + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice" +) + +type RequestFactory interface { + FullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (req *spacesyncproto.ObjectSyncMessage, err error) + FullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (*spacesyncproto.ObjectSyncMessage, error) +} + +func newRequestFactory() RequestFactory { + return &requestFactory{} +} + +type requestFactory struct{} + +func (r *requestFactory) FullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (msg *spacesyncproto.ObjectSyncMessage, err error) { + req := &spacesyncproto.ObjectFullSyncRequest{} + if t == nil { + msg = spacesyncproto.WrapFullRequest(req, t.Header(), t.ID(), trackingId) + return + } + + req.Heads = t.Heads() + req.SnapshotPath = t.SnapshotPath() + + var changesAfterSnapshot []*treechangeproto.RawTreeChangeWithId + changesAfterSnapshot, err = t.ChangesAfterCommonSnapshot(theirSnapshotPath, theirHeads) + if err != nil { + return + } + + req.Changes = changesAfterSnapshot + msg = spacesyncproto.WrapFullRequest(req, t.Header(), t.ID(), trackingId) + return +} + +func (r *requestFactory) FullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (msg *spacesyncproto.ObjectSyncMessage, err error) { + resp := &spacesyncproto.ObjectFullSyncResponse{ + Heads: t.Heads(), + SnapshotPath: t.SnapshotPath(), + } + if slice.UnsortedEquals(theirHeads, t.Heads()) { + msg = spacesyncproto.WrapFullResponse(resp, t.Header(), t.ID(), trackingId) + return + } + + ourChanges, err := t.ChangesAfterCommonSnapshot(theirSnapshotPath, theirHeads) + if err != nil { + return + } + resp.Changes = ourChanges + msg = spacesyncproto.WrapFullResponse(resp, t.Header(), t.ID(), trackingId) + return +} diff --git a/common/commonspace/syncservice/synchandler.go b/common/commonspace/syncservice/synchandler.go index 0123cbff..16ce2177 100644 --- a/common/commonspace/syncservice/synchandler.go +++ b/common/commonspace/syncservice/synchandler.go @@ -6,7 +6,6 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree" - "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice" ) @@ -14,17 +13,19 @@ type syncHandler struct { spaceId string treeCache cache.TreeCache syncClient SyncClient + factory RequestFactory } type SyncHandler interface { HandleMessage(ctx context.Context, senderId string, request *spacesyncproto.ObjectSyncMessage) (err error) } -func newSyncHandler(spaceId string, treeCache cache.TreeCache, syncClient SyncClient) *syncHandler { +func newSyncHandler(spaceId string, treeCache cache.TreeCache, syncClient SyncClient, factory RequestFactory) *syncHandler { return &syncHandler{ spaceId: spaceId, treeCache: treeCache, syncClient: syncClient, + factory: factory, } } @@ -47,10 +48,7 @@ func (s *syncHandler) handleHeadUpdate( update *spacesyncproto.ObjectHeadUpdate, msg *spacesyncproto.ObjectSyncMessage) (err error) { - var ( - fullRequest *spacesyncproto.ObjectFullSyncRequest - result tree.AddResult - ) + var fullRequest *spacesyncproto.ObjectSyncMessage res, err := s.treeCache.GetTree(ctx, s.spaceId, msg.TreeId) if err != nil { return @@ -62,21 +60,20 @@ func (s *syncHandler) handleHeadUpdate( defer res.Release() defer objTree.Unlock() - if slice.UnsortedEquals(update.Heads, objTree.Heads()) { + if s.alreadyHaveHeads(objTree, update.Heads) { return nil } - result, err = objTree.AddRawChanges(ctx, update.Changes...) + _, err = objTree.AddRawChanges(ctx, update.Changes...) if err != nil { return err } - // if after the heads are equal, or we have them locally - if slice.UnsortedEquals(update.Heads, result.Heads) || objTree.HasChanges(update.Heads...) { + if s.alreadyHaveHeads(objTree, update.Heads) { return nil } - fullRequest, err = s.prepareFullSyncRequest(objTree, update) + fullRequest, err = s.factory.FullSyncRequest(objTree, update.Heads, update.SnapshotPath, msg.TrackingId) if err != nil { return err } @@ -84,8 +81,7 @@ func (s *syncHandler) handleHeadUpdate( }() if fullRequest != nil { - return s.syncClient.SendAsync(senderId, - spacesyncproto.WrapFullRequest(fullRequest, msg.RootChange, msg.TreeId, msg.TrackingId)) + return s.syncClient.SendAsync(senderId, fullRequest) } return } @@ -96,7 +92,7 @@ func (s *syncHandler) handleFullSyncRequest( request *spacesyncproto.ObjectFullSyncRequest, msg *spacesyncproto.ObjectSyncMessage) (err error) { var ( - fullResponse *spacesyncproto.ObjectFullSyncResponse + fullResponse *spacesyncproto.ObjectSyncMessage header = msg.RootChange ) defer func() { @@ -120,20 +116,21 @@ func (s *syncHandler) handleFullSyncRequest( header = objTree.Header() } - _, err = objTree.AddRawChanges(ctx, request.Changes...) - if err != nil { - return err + if !s.alreadyHaveHeads(objTree, request.Heads) { + _, err = objTree.AddRawChanges(ctx, request.Changes...) + if err != nil { + return err + } } - fullResponse, err = s.prepareFullSyncResponse(request.SnapshotPath, request.Heads, objTree) + fullResponse, err = s.factory.FullSyncResponse(objTree, request.Heads, request.SnapshotPath, msg.TrackingId) return err }() if err != nil { return } - return s.syncClient.SendAsync(senderId, - spacesyncproto.WrapFullResponse(fullResponse, header, msg.TreeId, msg.TrackingId)) + return s.syncClient.SendAsync(senderId, fullResponse) } func (s *syncHandler) handleFullSyncResponse( @@ -152,8 +149,7 @@ func (s *syncHandler) handleFullSyncResponse( defer res.Release() defer objTree.Unlock() - // if we already have the heads for whatever reason - if slice.UnsortedEquals(response.Heads, objTree.Heads()) { + if s.alreadyHaveHeads(objTree, response.Heads) { return nil } @@ -164,39 +160,6 @@ func (s *syncHandler) handleFullSyncResponse( return } -func (s *syncHandler) prepareFullSyncRequest( - t tree.ObjectTree, - update *spacesyncproto.ObjectHeadUpdate) (req *spacesyncproto.ObjectFullSyncRequest, err error) { - req = &spacesyncproto.ObjectFullSyncRequest{ - Heads: t.Heads(), - SnapshotPath: t.SnapshotPath(), - } - if len(update.Changes) != 0 { - var changesAfterSnapshot []*treechangeproto.RawTreeChangeWithId - changesAfterSnapshot, err = t.ChangesAfterCommonSnapshot(update.SnapshotPath, update.Heads) - if err != nil { - return - } - req.Changes = changesAfterSnapshot - } - return &spacesyncproto.ObjectFullSyncRequest{ - Heads: t.Heads(), - SnapshotPath: t.SnapshotPath(), - }, nil -} - -func (s *syncHandler) prepareFullSyncResponse( - theirPath, - theirHeads []string, - t tree.ObjectTree) (*spacesyncproto.ObjectFullSyncResponse, error) { - ourChanges, err := t.ChangesAfterCommonSnapshot(theirPath, theirHeads) - if err != nil { - return nil, err - } - - return &spacesyncproto.ObjectFullSyncResponse{ - Heads: t.Heads(), - Changes: ourChanges, - SnapshotPath: t.SnapshotPath(), - }, nil +func (s *syncHandler) alreadyHaveHeads(t tree.ObjectTree, heads []string) bool { + return slice.UnsortedEquals(t.Heads(), heads) || t.HasChanges(heads...) } diff --git a/common/commonspace/syncservice/syncservice.go b/common/commonspace/syncservice/syncservice.go index 64ac67a6..c0a461e1 100644 --- a/common/commonspace/syncservice/syncservice.go +++ b/common/commonspace/syncservice/syncservice.go @@ -50,7 +50,7 @@ func NewSyncService(spaceId string, headNotifiable HeadNotifiable, cache cache.T streamPool := newStreamPool(func(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) { return syncHandler.HandleMessage(ctx, senderId, message) }) - syncHandler = newSyncHandler(spaceId, cache, streamPool) + syncHandler = newSyncHandler(spaceId, cache, streamPool, newRequestFactory()) return newSyncService( spaceId, headNotifiable, From 274573df284b8d52e74d8d6411e8f9a87092dda4 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Sun, 2 Oct 2022 16:11:47 +0200 Subject: [PATCH 13/17] Further updates to sync logic --- common/commonspace/rpchandler.go | 2 +- common/commonspace/space.go | 11 +- .../mock_syncservice/mock_syncservice.go | 130 +++++++++++++++++- .../commonspace/syncservice/requestfactory.go | 26 +++- common/commonspace/syncservice/streampool.go | 37 +++-- common/commonspace/syncservice/syncclient.go | 49 +++++++ common/commonspace/syncservice/synchandler.go | 42 +++--- .../syncservice/synchandler_test.go | 9 +- common/commonspace/syncservice/syncservice.go | 54 +++----- common/commonspace/synctree/synctree.go | 66 ++++----- 10 files changed, 303 insertions(+), 123 deletions(-) create mode 100644 common/commonspace/syncservice/syncclient.go diff --git a/common/commonspace/rpchandler.go b/common/commonspace/rpchandler.go index dbc5b7aa..73698856 100644 --- a/common/commonspace/rpchandler.go +++ b/common/commonspace/rpchandler.go @@ -19,5 +19,5 @@ func (r *rpcHandler) HeadSync(ctx context.Context, req *spacesyncproto.HeadSyncR } func (r *rpcHandler) Stream(stream spacesyncproto.DRPCSpace_StreamStream) (err error) { - return r.s.SyncService().StreamPool().AddAndReadStreamSync(stream) + return r.s.SyncService().SyncClient().AddAndReadStreamSync(stream) } diff --git a/common/commonspace/space.go b/common/commonspace/space.go index 46099da3..8111895a 100644 --- a/common/commonspace/space.go +++ b/common/commonspace/space.go @@ -90,11 +90,11 @@ func (s *space) DiffService() diffservice.DiffService { } func (s *space) DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error) { - return synctree.DeriveSyncTree(ctx, payload, s.syncService, listener, s.aclList, s.storage.CreateTreeStorage) + return synctree.DeriveSyncTree(ctx, payload, s.syncService.SyncClient(), listener, s.aclList, s.storage.CreateTreeStorage) } func (s *space) CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error) { - return synctree.CreateSyncTree(ctx, payload, s.syncService, listener, s.aclList, s.storage.CreateTreeStorage) + return synctree.CreateSyncTree(ctx, payload, s.syncService.SyncClient(), listener, s.aclList, s.storage.CreateTreeStorage) } func (s *space) BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (t tree.ObjectTree, err error) { @@ -104,10 +104,9 @@ func (s *space) BuildTree(ctx context.Context, id string, listener updatelistene if err != nil { return nil, err } - - return s.syncService.StreamPool().SendSync( + return s.syncService.SyncClient().SendSync( peerId, - spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{}, nil, id, ""), + s.syncService.SyncClient().CreateNewTreeRequest(id), ) } @@ -142,7 +141,7 @@ func (s *space) BuildTree(ctx context.Context, id string, listener updatelistene return } } - return synctree.BuildSyncTree(ctx, s.syncService, store.(treestorage.TreeStorage), listener, s.aclList) + return synctree.BuildSyncTree(ctx, s.syncService.SyncClient(), store.(treestorage.TreeStorage), listener, s.aclList) } func (s *space) Close() error { diff --git a/common/commonspace/syncservice/mock_syncservice/mock_syncservice.go b/common/commonspace/syncservice/mock_syncservice/mock_syncservice.go index 8438ab64..6f1a272b 100644 --- a/common/commonspace/syncservice/mock_syncservice/mock_syncservice.go +++ b/common/commonspace/syncservice/mock_syncservice/mock_syncservice.go @@ -8,6 +8,8 @@ import ( reflect "reflect" spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" + tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree" + treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" gomock "github.com/golang/mock/gomock" ) @@ -34,6 +36,32 @@ func (m *MockSyncClient) EXPECT() *MockSyncClientMockRecorder { return m.recorder } +// AddAndReadStreamAsync mocks base method. +func (m *MockSyncClient) AddAndReadStreamAsync(arg0 spacesyncproto.DRPCSpace_StreamStream) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "AddAndReadStreamAsync", arg0) +} + +// AddAndReadStreamAsync indicates an expected call of AddAndReadStreamAsync. +func (mr *MockSyncClientMockRecorder) AddAndReadStreamAsync(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAndReadStreamAsync", reflect.TypeOf((*MockSyncClient)(nil).AddAndReadStreamAsync), arg0) +} + +// AddAndReadStreamSync mocks base method. +func (m *MockSyncClient) AddAndReadStreamSync(arg0 spacesyncproto.DRPCSpace_StreamStream) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddAndReadStreamSync", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddAndReadStreamSync indicates an expected call of AddAndReadStreamSync. +func (mr *MockSyncClientMockRecorder) AddAndReadStreamSync(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAndReadStreamSync", reflect.TypeOf((*MockSyncClient)(nil).AddAndReadStreamSync), arg0) +} + // BroadcastAsync mocks base method. func (m *MockSyncClient) BroadcastAsync(arg0 *spacesyncproto.ObjectSyncMessage) error { m.ctrl.T.Helper() @@ -48,8 +76,108 @@ func (mr *MockSyncClientMockRecorder) BroadcastAsync(arg0 interface{}) *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastAsync", reflect.TypeOf((*MockSyncClient)(nil).BroadcastAsync), arg0) } +// BroadcastAsyncOrSendResponsible mocks base method. +func (m *MockSyncClient) BroadcastAsyncOrSendResponsible(arg0 *spacesyncproto.ObjectSyncMessage) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BroadcastAsyncOrSendResponsible", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// BroadcastAsyncOrSendResponsible indicates an expected call of BroadcastAsyncOrSendResponsible. +func (mr *MockSyncClientMockRecorder) BroadcastAsyncOrSendResponsible(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastAsyncOrSendResponsible", reflect.TypeOf((*MockSyncClient)(nil).BroadcastAsyncOrSendResponsible), arg0) +} + +// Close mocks base method. +func (m *MockSyncClient) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockSyncClientMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockSyncClient)(nil).Close)) +} + +// CreateFullSyncRequest mocks base method. +func (m *MockSyncClient) CreateFullSyncRequest(arg0 tree.ObjectTree, arg1, arg2 []string, arg3 string) (*spacesyncproto.ObjectSyncMessage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateFullSyncRequest", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateFullSyncRequest indicates an expected call of CreateFullSyncRequest. +func (mr *MockSyncClientMockRecorder) CreateFullSyncRequest(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFullSyncRequest", reflect.TypeOf((*MockSyncClient)(nil).CreateFullSyncRequest), arg0, arg1, arg2, arg3) +} + +// CreateFullSyncResponse mocks base method. +func (m *MockSyncClient) CreateFullSyncResponse(arg0 tree.ObjectTree, arg1, arg2 []string, arg3 string) (*spacesyncproto.ObjectSyncMessage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateFullSyncResponse", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateFullSyncResponse indicates an expected call of CreateFullSyncResponse. +func (mr *MockSyncClientMockRecorder) CreateFullSyncResponse(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFullSyncResponse", reflect.TypeOf((*MockSyncClient)(nil).CreateFullSyncResponse), arg0, arg1, arg2, arg3) +} + +// CreateHeadUpdate mocks base method. +func (m *MockSyncClient) CreateHeadUpdate(arg0 tree.ObjectTree, arg1 []*treechangeproto.RawTreeChangeWithId) *spacesyncproto.ObjectSyncMessage { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateHeadUpdate", arg0, arg1) + ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage) + return ret0 +} + +// CreateHeadUpdate indicates an expected call of CreateHeadUpdate. +func (mr *MockSyncClientMockRecorder) CreateHeadUpdate(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateHeadUpdate", reflect.TypeOf((*MockSyncClient)(nil).CreateHeadUpdate), arg0, arg1) +} + +// CreateNewTreeRequest mocks base method. +func (m *MockSyncClient) CreateNewTreeRequest(arg0 string) *spacesyncproto.ObjectSyncMessage { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateNewTreeRequest", arg0) + ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage) + return ret0 +} + +// CreateNewTreeRequest indicates an expected call of CreateNewTreeRequest. +func (mr *MockSyncClientMockRecorder) CreateNewTreeRequest(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNewTreeRequest", reflect.TypeOf((*MockSyncClient)(nil).CreateNewTreeRequest), arg0) +} + +// HasActiveStream mocks base method. +func (m *MockSyncClient) HasActiveStream(arg0 string) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasActiveStream", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// HasActiveStream indicates an expected call of HasActiveStream. +func (mr *MockSyncClientMockRecorder) HasActiveStream(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasActiveStream", reflect.TypeOf((*MockSyncClient)(nil).HasActiveStream), arg0) +} + // SendAsync mocks base method. -func (m *MockSyncClient) SendAsync(arg0 string, arg1 *spacesyncproto.ObjectSyncMessage) error { +func (m *MockSyncClient) SendAsync(arg0 []string, arg1 *spacesyncproto.ObjectSyncMessage) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SendAsync", arg0, arg1) ret0, _ := ret[0].(error) diff --git a/common/commonspace/syncservice/requestfactory.go b/common/commonspace/syncservice/requestfactory.go index ab19bc6a..1237653b 100644 --- a/common/commonspace/syncservice/requestfactory.go +++ b/common/commonspace/syncservice/requestfactory.go @@ -1,6 +1,7 @@ package syncservice import ( + "fmt" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" @@ -8,8 +9,10 @@ import ( ) type RequestFactory interface { - FullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (req *spacesyncproto.ObjectSyncMessage, err error) - FullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (*spacesyncproto.ObjectSyncMessage, error) + CreateHeadUpdate(t tree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *spacesyncproto.ObjectSyncMessage) + CreateNewTreeRequest(id string) (msg *spacesyncproto.ObjectSyncMessage) + CreateFullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (req *spacesyncproto.ObjectSyncMessage, err error) + CreateFullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (*spacesyncproto.ObjectSyncMessage, error) } func newRequestFactory() RequestFactory { @@ -18,11 +21,22 @@ func newRequestFactory() RequestFactory { type requestFactory struct{} -func (r *requestFactory) FullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (msg *spacesyncproto.ObjectSyncMessage, err error) { +func (r *requestFactory) CreateHeadUpdate(t tree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *spacesyncproto.ObjectSyncMessage) { + return spacesyncproto.WrapHeadUpdate(&spacesyncproto.ObjectHeadUpdate{ + Heads: t.Heads(), + Changes: added, + SnapshotPath: t.SnapshotPath(), + }, t.Header(), t.ID(), "") +} + +func (r *requestFactory) CreateNewTreeRequest(id string) (msg *spacesyncproto.ObjectSyncMessage) { + return spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{}, nil, id, "") +} + +func (r *requestFactory) CreateFullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (msg *spacesyncproto.ObjectSyncMessage, err error) { req := &spacesyncproto.ObjectFullSyncRequest{} if t == nil { - msg = spacesyncproto.WrapFullRequest(req, t.Header(), t.ID(), trackingId) - return + return nil, fmt.Errorf("tree should not be empty") } req.Heads = t.Heads() @@ -39,7 +53,7 @@ func (r *requestFactory) FullSyncRequest(t tree.ObjectTree, theirHeads, theirSna return } -func (r *requestFactory) FullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (msg *spacesyncproto.ObjectSyncMessage, err error) { +func (r *requestFactory) CreateFullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (msg *spacesyncproto.ObjectSyncMessage, err error) { resp := &spacesyncproto.ObjectFullSyncResponse{ Heads: t.Heads(), SnapshotPath: t.SnapshotPath(), diff --git a/common/commonspace/syncservice/streampool.go b/common/commonspace/syncservice/streampool.go index 5eb97170..bf457374 100644 --- a/common/commonspace/syncservice/streampool.go +++ b/common/commonspace/syncservice/streampool.go @@ -18,16 +18,16 @@ const maxSimultaneousOperationsPerStream = 10 // StreamPool can be made generic to work with different streams type StreamPool interface { - SyncClient + Sender AddAndReadStreamSync(stream spacesyncproto.SpaceStream) (err error) AddAndReadStreamAsync(stream spacesyncproto.SpaceStream) HasActiveStream(peerId string) bool Close() (err error) } -type SyncClient interface { +type Sender interface { SendSync(peerId string, message *spacesyncproto.ObjectSyncMessage) (reply *spacesyncproto.ObjectSyncMessage, err error) - SendAsync(peerId string, message *spacesyncproto.ObjectSyncMessage) (err error) + SendAsync(peers []string, message *spacesyncproto.ObjectSyncMessage) (err error) BroadcastAsync(message *spacesyncproto.ObjectSyncMessage) (err error) } @@ -56,6 +56,8 @@ func newStreamPool(messageHandler MessageHandler) StreamPool { } func (s *streamPool) HasActiveStream(peerId string) (res bool) { + s.Lock() + defer s.Unlock() _, err := s.getOrDeleteStream(peerId) return err == nil } @@ -73,7 +75,7 @@ func (s *streamPool) SendSync( s.waiters[msg.TrackingId] = waiter s.waitersMx.Unlock() - err = s.SendAsync(peerId, msg) + err = s.SendAsync([]string{peerId}, msg) if err != nil { return } @@ -82,18 +84,31 @@ func (s *streamPool) SendSync( return } -func (s *streamPool) SendAsync(peerId string, message *spacesyncproto.ObjectSyncMessage) (err error) { - stream, err := s.getOrDeleteStream(peerId) - if err != nil { - return +func (s *streamPool) SendAsync(peers []string, message *spacesyncproto.ObjectSyncMessage) (err error) { + getStreams := func() (streams []spacesyncproto.SpaceStream) { + for _, pId := range peers { + stream, err := s.getOrDeleteStream(pId) + if err != nil { + continue + } + streams = append(streams, stream) + } + return streams } - return stream.Send(message) + s.Lock() + streams := getStreams() + s.Unlock() + + for _, s := range streams { + if len(peers) == 1 { + err = s.Send(message) + } + } + return err } func (s *streamPool) getOrDeleteStream(id string) (stream spacesyncproto.SpaceStream, err error) { - s.Lock() - defer s.Unlock() stream, exists := s.peerStreams[id] if !exists { err = ErrEmptyPeer diff --git a/common/commonspace/syncservice/syncclient.go b/common/commonspace/syncservice/syncclient.go new file mode 100644 index 00000000..12c25164 --- /dev/null +++ b/common/commonspace/syncservice/syncclient.go @@ -0,0 +1,49 @@ +package syncservice + +import ( + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" +) + +type SyncClient interface { + StreamPool + RequestFactory + BroadcastAsyncOrSendResponsible(message *spacesyncproto.ObjectSyncMessage) (err error) +} + +type syncClient struct { + StreamPool + RequestFactory + spaceId string + notifiable HeadNotifiable + configuration nodeconf.Configuration +} + +func newSyncClient(spaceId string, pool StreamPool, notifiable HeadNotifiable, factory RequestFactory, configuration nodeconf.Configuration) SyncClient { + return &syncClient{ + StreamPool: pool, + RequestFactory: factory, + notifiable: notifiable, + configuration: configuration, + spaceId: spaceId, + } +} + +func (s *syncClient) BroadcastAsync(message *spacesyncproto.ObjectSyncMessage) (err error) { + s.notifyIfNeeded(message) + return s.BroadcastAsync(message) +} + +func (s *syncClient) BroadcastAsyncOrSendResponsible(message *spacesyncproto.ObjectSyncMessage) (err error) { + if s.configuration.IsResponsible(s.spaceId) { + return s.SendAsync(s.configuration.NodeIds(s.spaceId), message) + } + return s.BroadcastAsync(message) +} + +func (s *syncClient) notifyIfNeeded(message *spacesyncproto.ObjectSyncMessage) { + if message.GetContent().GetHeadUpdate() != nil { + update := message.GetContent().GetHeadUpdate() + s.notifiable.UpdateHeads(message.TreeId, update.Heads) + } +} diff --git a/common/commonspace/syncservice/synchandler.go b/common/commonspace/syncservice/synchandler.go index 16ce2177..d0edf03c 100644 --- a/common/commonspace/syncservice/synchandler.go +++ b/common/commonspace/syncservice/synchandler.go @@ -1,4 +1,3 @@ -//go:generate mockgen -destination mock_syncservice/mock_syncservice.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice SyncClient package syncservice import ( @@ -13,19 +12,17 @@ type syncHandler struct { spaceId string treeCache cache.TreeCache syncClient SyncClient - factory RequestFactory } type SyncHandler interface { HandleMessage(ctx context.Context, senderId string, request *spacesyncproto.ObjectSyncMessage) (err error) } -func newSyncHandler(spaceId string, treeCache cache.TreeCache, syncClient SyncClient, factory RequestFactory) *syncHandler { +func newSyncHandler(spaceId string, treeCache cache.TreeCache, syncClient SyncClient) *syncHandler { return &syncHandler{ spaceId: spaceId, treeCache: treeCache, syncClient: syncClient, - factory: factory, } } @@ -48,7 +45,10 @@ func (s *syncHandler) handleHeadUpdate( update *spacesyncproto.ObjectHeadUpdate, msg *spacesyncproto.ObjectSyncMessage) (err error) { - var fullRequest *spacesyncproto.ObjectSyncMessage + var ( + fullRequest *spacesyncproto.ObjectSyncMessage + isEmptyUpdate = len(update.Changes) == 0 + ) res, err := s.treeCache.GetTree(ctx, s.spaceId, msg.TreeId) if err != nil { return @@ -60,7 +60,14 @@ func (s *syncHandler) handleHeadUpdate( defer res.Release() defer objTree.Unlock() - if s.alreadyHaveHeads(objTree, update.Heads) { + // isEmptyUpdate is sent when the tree is brought up from cache + if isEmptyUpdate { + // we need to sync in any case + fullRequest, err = s.syncClient.CreateFullSyncRequest(objTree, update.Heads, update.SnapshotPath, msg.TrackingId) + return err + } + + if s.alreadyHasHeads(objTree, update.Heads) { return nil } @@ -69,19 +76,16 @@ func (s *syncHandler) handleHeadUpdate( return err } - if s.alreadyHaveHeads(objTree, update.Heads) { + if s.alreadyHasHeads(objTree, update.Heads) { return nil } - fullRequest, err = s.factory.FullSyncRequest(objTree, update.Heads, update.SnapshotPath, msg.TrackingId) - if err != nil { - return err - } - return nil + fullRequest, err = s.syncClient.CreateFullSyncRequest(objTree, update.Heads, update.SnapshotPath, msg.TrackingId) + return err }() if fullRequest != nil { - return s.syncClient.SendAsync(senderId, fullRequest) + return s.syncClient.SendAsync([]string{senderId}, fullRequest) } return } @@ -97,7 +101,7 @@ func (s *syncHandler) handleFullSyncRequest( ) defer func() { if err != nil { - s.syncClient.SendAsync(senderId, spacesyncproto.WrapError(err, header, msg.TreeId, msg.TrackingId)) + s.syncClient.SendAsync([]string{senderId}, spacesyncproto.WrapError(err, header, msg.TreeId, msg.TrackingId)) } }() @@ -116,21 +120,21 @@ func (s *syncHandler) handleFullSyncRequest( header = objTree.Header() } - if !s.alreadyHaveHeads(objTree, request.Heads) { + if !s.alreadyHasHeads(objTree, request.Heads) { _, err = objTree.AddRawChanges(ctx, request.Changes...) if err != nil { return err } } - fullResponse, err = s.factory.FullSyncResponse(objTree, request.Heads, request.SnapshotPath, msg.TrackingId) + fullResponse, err = s.syncClient.CreateFullSyncResponse(objTree, request.Heads, request.SnapshotPath, msg.TrackingId) return err }() if err != nil { return } - return s.syncClient.SendAsync(senderId, fullResponse) + return s.syncClient.SendAsync([]string{senderId}, fullResponse) } func (s *syncHandler) handleFullSyncResponse( @@ -149,7 +153,7 @@ func (s *syncHandler) handleFullSyncResponse( defer res.Release() defer objTree.Unlock() - if s.alreadyHaveHeads(objTree, response.Heads) { + if s.alreadyHasHeads(objTree, response.Heads) { return nil } @@ -160,6 +164,6 @@ func (s *syncHandler) handleFullSyncResponse( return } -func (s *syncHandler) alreadyHaveHeads(t tree.ObjectTree, heads []string) bool { +func (s *syncHandler) alreadyHasHeads(t tree.ObjectTree, heads []string) bool { return slice.UnsortedEquals(t.Heads(), heads) || t.HasChanges(heads...) } diff --git a/common/commonspace/syncservice/synchandler_test.go b/common/commonspace/syncservice/synchandler_test.go index dc145017..e8fa2b63 100644 --- a/common/commonspace/syncservice/synchandler_test.go +++ b/common/commonspace/syncservice/synchandler_test.go @@ -48,9 +48,12 @@ func TestSyncHandler_HandleMessage(t *testing.T) { 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})). + 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) diff --git a/common/commonspace/syncservice/syncservice.go b/common/commonspace/syncservice/syncservice.go index c0a461e1..d065832a 100644 --- a/common/commonspace/syncservice/syncservice.go +++ b/common/commonspace/syncservice/syncservice.go @@ -1,3 +1,4 @@ +//go:generate mockgen -destination mock_syncservice/mock_syncservice.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice SyncClient package syncservice import ( @@ -7,19 +8,13 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" - "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" "time" ) var log = logger.NewNamed("syncservice").Sugar() type SyncService interface { - NotifyHeadUpdate( - ctx context.Context, - treeId string, - root *treechangeproto.RawTreeChangeWithId, - update *spacesyncproto.ObjectHeadUpdate) (err error) - StreamPool() StreamPool + SyncClient() SyncClient Init() Close() (err error) @@ -34,11 +29,9 @@ const respPeersStreamCheckInterval = time.Second * 10 type syncService struct { spaceId string - syncHandler SyncHandler - streamPool StreamPool - headNotifiable HeadNotifiable - configuration nodeconf.Configuration - clientFactory spacesyncproto.ClientFactory + syncClient SyncClient + configuration nodeconf.Configuration + clientFactory spacesyncproto.ClientFactory streamLoopCtx context.Context stopStreamLoop context.CancelFunc @@ -47,30 +40,26 @@ type syncService struct { func NewSyncService(spaceId string, headNotifiable HeadNotifiable, cache cache.TreeCache, configuration nodeconf.Configuration) SyncService { var syncHandler SyncHandler - streamPool := newStreamPool(func(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) { + pool := newStreamPool(func(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) { return syncHandler.HandleMessage(ctx, senderId, message) }) - syncHandler = newSyncHandler(spaceId, cache, streamPool, newRequestFactory()) + factory := newRequestFactory() + syncClient := newSyncClient(spaceId, pool, headNotifiable, factory, configuration) + syncHandler = newSyncHandler(spaceId, cache, syncClient) return newSyncService( spaceId, - headNotifiable, - syncHandler, - streamPool, + syncClient, spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient), configuration) } func newSyncService( spaceId string, - headNotifiable HeadNotifiable, - syncHandler SyncHandler, - streamPool StreamPool, + syncClient SyncClient, clientFactory spacesyncproto.ClientFactory, configuration nodeconf.Configuration) *syncService { return &syncService{ - syncHandler: syncHandler, - streamPool: streamPool, - headNotifiable: headNotifiable, + syncClient: syncClient, configuration: configuration, clientFactory: clientFactory, spaceId: spaceId, @@ -86,16 +75,7 @@ func (s *syncService) Init() { func (s *syncService) Close() (err error) { s.stopStreamLoop() <-s.streamLoopDone - return s.streamPool.Close() -} - -func (s *syncService) NotifyHeadUpdate( - ctx context.Context, - treeId string, - header *treechangeproto.RawTreeChangeWithId, - update *spacesyncproto.ObjectHeadUpdate) (err error) { - s.headNotifiable.UpdateHeads(treeId, update.Heads) - return s.streamPool.BroadcastAsync(spacesyncproto.WrapHeadUpdate(update, header, treeId, "")) + return s.syncClient.Close() } func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) { @@ -106,7 +86,7 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) { return } for _, peer := range respPeers { - if s.streamPool.HasActiveStream(peer.Id()) { + if s.syncClient.HasActiveStream(peer.Id()) { continue } stream, err := s.clientFactory.Client(peer).Stream(ctx) @@ -124,7 +104,7 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) { log.With("spaceId", s.spaceId).Errorf("failed to send first message to stream: %v", err) continue } - s.streamPool.AddAndReadStreamAsync(stream) + s.syncClient.AddAndReadStreamAsync(stream) } } @@ -141,6 +121,6 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) { } } -func (s *syncService) StreamPool() StreamPool { - return s.streamPool +func (s *syncService) SyncClient() SyncClient { + return s.syncClient } diff --git a/common/commonspace/synctree/synctree.go b/common/commonspace/synctree/synctree.go index f3075825..99c6014d 100644 --- a/common/commonspace/synctree/synctree.go +++ b/common/commonspace/synctree/synctree.go @@ -2,7 +2,6 @@ package synctree import ( "context" - "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list" @@ -14,14 +13,14 @@ import ( // SyncTree sends head updates to sync service and also sends new changes to update listener type SyncTree struct { tree.ObjectTree - syncService syncservice.SyncService - listener updatelistener.UpdateListener + syncClient syncservice.SyncClient + listener updatelistener.UpdateListener } func DeriveSyncTree( ctx context.Context, payload tree.ObjectTreeCreatePayload, - syncService syncservice.SyncService, + syncClient syncservice.SyncClient, listener updatelistener.UpdateListener, aclList list.ACLList, createStorage storage.TreeStorageCreatorFunc) (t tree.ObjectTree, err error) { @@ -30,22 +29,20 @@ func DeriveSyncTree( return } t = &SyncTree{ - ObjectTree: t, - syncService: syncService, - listener: listener, + ObjectTree: t, + syncClient: syncClient, + listener: listener, } - err = syncService.NotifyHeadUpdate(ctx, t.ID(), t.Header(), &spacesyncproto.ObjectHeadUpdate{ - Heads: t.Heads(), - SnapshotPath: t.SnapshotPath(), - }) + headUpdate := syncClient.CreateHeadUpdate(t, nil) + err = syncClient.BroadcastAsync(headUpdate) return } func CreateSyncTree( ctx context.Context, payload tree.ObjectTreeCreatePayload, - syncService syncservice.SyncService, + syncClient syncservice.SyncClient, listener updatelistener.UpdateListener, aclList list.ACLList, createStorage storage.TreeStorageCreatorFunc) (t tree.ObjectTree, err error) { @@ -54,30 +51,28 @@ func CreateSyncTree( return } t = &SyncTree{ - ObjectTree: t, - syncService: syncService, - listener: listener, + ObjectTree: t, + syncClient: syncClient, + listener: listener, } - err = syncService.NotifyHeadUpdate(ctx, t.ID(), t.Header(), &spacesyncproto.ObjectHeadUpdate{ - Heads: t.Heads(), - SnapshotPath: t.SnapshotPath(), - }) + headUpdate := syncClient.CreateHeadUpdate(t, nil) + err = syncClient.BroadcastAsync(headUpdate) return } func BuildSyncTree( ctx context.Context, - syncService syncservice.SyncService, + syncClient syncservice.SyncClient, treeStorage storage.TreeStorage, listener updatelistener.UpdateListener, aclList list.ACLList) (t tree.ObjectTree, err error) { - return buildSyncTree(ctx, syncService, treeStorage, listener, aclList) + return buildSyncTree(ctx, syncClient, treeStorage, listener, aclList) } func buildSyncTree( ctx context.Context, - syncService syncservice.SyncService, + syncClient syncservice.SyncClient, treeStorage storage.TreeStorage, listener updatelistener.UpdateListener, aclList list.ACLList) (t tree.ObjectTree, err error) { @@ -86,15 +81,14 @@ func buildSyncTree( return } t = &SyncTree{ - ObjectTree: t, - syncService: syncService, - listener: listener, + ObjectTree: t, + syncClient: syncClient, + listener: listener, } - err = syncService.NotifyHeadUpdate(ctx, t.ID(), t.Header(), &spacesyncproto.ObjectHeadUpdate{ - Heads: t.Heads(), - SnapshotPath: t.SnapshotPath(), - }) + headUpdate := syncClient.CreateHeadUpdate(t, nil) + // here we will have different behaviour based on who is sending this update + err = syncClient.BroadcastAsyncOrSendResponsible(headUpdate) return } @@ -103,11 +97,8 @@ func (s *SyncTree) AddContent(ctx context.Context, content tree.SignableChangeCo if err != nil { return } - err = s.syncService.NotifyHeadUpdate(ctx, s.ID(), s.Header(), &spacesyncproto.ObjectHeadUpdate{ - Heads: res.Heads, - Changes: res.Added, - SnapshotPath: s.SnapshotPath(), - }) + headUpdate := s.syncClient.CreateHeadUpdate(s, res.Added) + err = s.syncClient.BroadcastAsync(headUpdate) return } @@ -125,11 +116,8 @@ func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*treechangeprot s.listener.Rebuild(s) } - err = s.syncService.NotifyHeadUpdate(ctx, s.ID(), s.Header(), &spacesyncproto.ObjectHeadUpdate{ - Heads: res.Heads, - Changes: res.Added, - SnapshotPath: s.SnapshotPath(), - }) + headUpdate := s.syncClient.CreateHeadUpdate(s, res.Added) + err = s.syncClient.BroadcastAsync(headUpdate) return } From d7a2a1212964acc2e4799c86adc5297687706aff Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Sun, 2 Oct 2022 22:40:13 +0200 Subject: [PATCH 14/17] 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) + }) } From 86616b6936e666500e8c8aef3c4223cbaa71a6c8 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Mon, 3 Oct 2022 23:35:25 +0200 Subject: [PATCH 15/17] Add sync handler tests --- common/commonspace/syncservice/synchandler.go | 2 +- .../syncservice/synchandler_test.go | 230 ++++++++++++++++-- 2 files changed, 210 insertions(+), 22 deletions(-) diff --git a/common/commonspace/syncservice/synchandler.go b/common/commonspace/syncservice/synchandler.go index 500e6e7b..d74645c4 100644 --- a/common/commonspace/syncservice/synchandler.go +++ b/common/commonspace/syncservice/synchandler.go @@ -123,7 +123,7 @@ func (s *syncHandler) handleFullSyncRequest( header = objTree.Header() } - if !s.alreadyHasHeads(objTree, request.Heads) { + if len(request.Changes) != 0 && !s.alreadyHasHeads(objTree, request.Heads) { _, err = objTree.AddRawChanges(ctx, request.Changes...) if err != nil { return err diff --git a/common/commonspace/syncservice/synchandler_test.go b/common/commonspace/syncservice/synchandler_test.go index 611dfeff..3b16725e 100644 --- a/common/commonspace/syncservice/synchandler_test.go +++ b/common/commonspace/syncservice/synchandler_test.go @@ -2,6 +2,7 @@ package syncservice import ( "context" + "fmt" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache/mock_cache" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" @@ -11,6 +12,7 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + "sync" "testing" ) @@ -22,6 +24,25 @@ func (t treeContainer) Tree() tree.ObjectTree { return t.objTree } +type testObjTreeMock struct { + *mock_tree.MockObjectTree + m sync.Mutex +} + +func newTestObjMock(mockTree *mock_tree.MockObjectTree) *testObjTreeMock { + return &testObjTreeMock{ + MockObjectTree: mockTree, + } +} + +func (t *testObjTreeMock) Lock() { + t.m.Lock() +} + +func (t *testObjTreeMock) Unlock() { + t.m.Unlock() +} + func TestSyncHandler_HandleHeadUpdate(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -30,7 +51,7 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) { spaceId := "spaceId" cacheMock := mock_cache.NewMockTreeCache(ctrl) syncClientMock := mock_syncservice.NewMockSyncClient(ctrl) - objectTreeMock := mock_tree.NewMockObjectTree(ctrl) + objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl)) syncHandler := newSyncHandler(spaceId, cacheMock, syncClientMock) t.Run("head update non empty all heads added", func(t *testing.T) { @@ -49,8 +70,6 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) { Release: func() {}, TreeContainer: treeContainer{objectTreeMock}, }, nil) - objectTreeMock.EXPECT(). - Lock() objectTreeMock.EXPECT(). Heads(). Return([]string{"h2"}) @@ -66,8 +85,6 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) { objectTreeMock.EXPECT(). HasChanges(gomock.Eq([]string{"h1"})). Return(true) - objectTreeMock.EXPECT(). - Unlock() err := syncHandler.HandleMessage(ctx, senderId, msg) require.NoError(t, err) @@ -90,8 +107,6 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) { Release: func() {}, TreeContainer: treeContainer{objectTreeMock}, }, nil) - objectTreeMock.EXPECT(). - Lock() objectTreeMock.EXPECT(). Heads(). Return([]string{"h2"}) @@ -110,8 +125,6 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) { 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) @@ -134,13 +147,9 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) { 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) @@ -163,16 +172,12 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) { 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) @@ -195,13 +200,196 @@ func TestSyncHandler_HandleHeadUpdate(t *testing.T) { Release: func() {}, TreeContainer: treeContainer{objectTreeMock}, }, nil) - objectTreeMock.EXPECT(). - Lock() + + objectTreeMock.EXPECT(). + Heads(). + Return([]string{"h1"}) + + err := syncHandler.HandleMessage(ctx, senderId, msg) + require.NoError(t, err) + }) +} + +func TestSyncHandler_HandleFullSyncRequest(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + ctx := context.Background() + spaceId := "spaceId" + cacheMock := mock_cache.NewMockTreeCache(ctrl) + syncClientMock := mock_syncservice.NewMockSyncClient(ctrl) + objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl)) + + syncHandler := newSyncHandler(spaceId, cacheMock, syncClientMock) + t.Run("full sync request with change", func(t *testing.T) { + treeId := "treeId" + senderId := "senderId" + chWithId := &treechangeproto.RawTreeChangeWithId{} + msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{ + Heads: []string{"h1"}, + Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, + SnapshotPath: []string{"h1"}, + }, chWithId, treeId, "") + fullRequest := &spacesyncproto.ObjectSyncMessage{} + + cacheMock.EXPECT(). + GetTree(gomock.Any(), spaceId, treeId). + Return(cache.TreeResult{ + Release: func() {}, + TreeContainer: treeContainer{objectTreeMock}, + }, nil) + 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) + syncClientMock.EXPECT(). + CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")). + Return(fullRequest, nil) + + syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest)) + err := syncHandler.HandleMessage(ctx, senderId, msg) + require.NoError(t, err) + }) + + t.Run("full sync request with change same heads", func(t *testing.T) { + treeId := "treeId" + senderId := "senderId" + chWithId := &treechangeproto.RawTreeChangeWithId{} + msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{ + Heads: []string{"h2"}, + Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, + SnapshotPath: []string{"h2"}, + }, chWithId, treeId, "") + fullRequest := &spacesyncproto.ObjectSyncMessage{} + + cacheMock.EXPECT(). + GetTree(gomock.Any(), spaceId, treeId). + Return(cache.TreeResult{ + Release: func() {}, + TreeContainer: treeContainer{objectTreeMock}, + }, nil) + objectTreeMock.EXPECT(). + Heads(). + Return([]string{"h2"}) + syncClientMock.EXPECT(). + CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h2"}), gomock.Eq([]string{"h2"}), gomock.Eq("")). + Return(fullRequest, nil) + + syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest)) + err := syncHandler.HandleMessage(ctx, senderId, msg) + require.NoError(t, err) + }) + + t.Run("full sync request without change", func(t *testing.T) { + treeId := "treeId" + senderId := "senderId" + chWithId := &treechangeproto.RawTreeChangeWithId{} + msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{ + Heads: []string{"h1"}, + SnapshotPath: []string{"h1"}, + }, chWithId, treeId, "") + fullRequest := &spacesyncproto.ObjectSyncMessage{} + + cacheMock.EXPECT(). + GetTree(gomock.Any(), spaceId, treeId). + Return(cache.TreeResult{ + Release: func() {}, + TreeContainer: treeContainer{objectTreeMock}, + }, nil) + syncClientMock.EXPECT(). + CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")). + Return(fullRequest, nil) + + syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest)) + err := syncHandler.HandleMessage(ctx, senderId, msg) + require.NoError(t, err) + }) + + t.Run("full sync request with get tree error", func(t *testing.T) { + treeId := "treeId" + senderId := "senderId" + chWithId := &treechangeproto.RawTreeChangeWithId{} + msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{ + Heads: []string{"h1"}, + SnapshotPath: []string{"h1"}, + }, chWithId, treeId, "") + + cacheMock.EXPECT(). + GetTree(gomock.Any(), spaceId, treeId). + Return(cache.TreeResult{}, fmt.Errorf("some")) + + syncClientMock.EXPECT(). + SendAsync(gomock.Eq([]string{senderId}), gomock.Any()) + err := syncHandler.HandleMessage(ctx, senderId, msg) + require.Error(t, err) + }) +} + +func TestSyncHandler_HandleFullSyncResponse(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + ctx := context.Background() + spaceId := "spaceId" + cacheMock := mock_cache.NewMockTreeCache(ctrl) + syncClientMock := mock_syncservice.NewMockSyncClient(ctrl) + objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl)) + + syncHandler := newSyncHandler(spaceId, cacheMock, syncClientMock) + t.Run("full sync response with change", func(t *testing.T) { + treeId := "treeId" + senderId := "senderId" + chWithId := &treechangeproto.RawTreeChangeWithId{} + msg := spacesyncproto.WrapFullResponse(&spacesyncproto.ObjectFullSyncResponse{ + Heads: []string{"h1"}, + Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, + SnapshotPath: []string{"h1"}, + }, chWithId, treeId, "") + + cacheMock.EXPECT(). + GetTree(gomock.Any(), spaceId, treeId). + Return(cache.TreeResult{ + Release: func() {}, + TreeContainer: treeContainer{objectTreeMock}, + }, nil) + 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) + + err := syncHandler.HandleMessage(ctx, senderId, msg) + require.NoError(t, err) + }) + + t.Run("full sync response same heads", func(t *testing.T) { + treeId := "treeId" + senderId := "senderId" + chWithId := &treechangeproto.RawTreeChangeWithId{} + msg := spacesyncproto.WrapFullResponse(&spacesyncproto.ObjectFullSyncResponse{ + Heads: []string{"h1"}, + Changes: []*treechangeproto.RawTreeChangeWithId{chWithId}, + SnapshotPath: []string{"h1"}, + }, chWithId, treeId, "") + + cacheMock.EXPECT(). + GetTree(gomock.Any(), spaceId, treeId). + Return(cache.TreeResult{ + Release: func() {}, + TreeContainer: treeContainer{objectTreeMock}, + }, nil) objectTreeMock.EXPECT(). Heads(). Return([]string{"h1"}) - objectTreeMock.EXPECT(). - Unlock() err := syncHandler.HandleMessage(ctx, senderId, msg) require.NoError(t, err) From 2999f2dcddd1da8662cbf8d1f89b20086af04040 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Sun, 9 Oct 2022 21:54:34 +0200 Subject: [PATCH 16/17] Add conf connector and change configuration logic --- common/commonspace/diffservice/diffservice.go | 4 +- common/commonspace/diffservice/diffsyncer.go | 8 +- .../diffservice/diffsyncer_test.go | 20 ++--- common/commonspace/service.go | 8 +- common/commonspace/syncservice/syncservice.go | 21 ++++-- common/nodeconf/confconnector.go | 54 ++++++++++++++ common/nodeconf/configuration.go | 47 +----------- .../nodeconf/mock_nodeconf/mock_nodeconf.go | 74 ++++++++++--------- common/nodeconf/service.go | 4 - go.mod | 3 + go.sum | 2 + 11 files changed, 136 insertions(+), 109 deletions(-) create mode 100644 common/nodeconf/confconnector.go diff --git a/common/commonspace/diffservice/diffservice.go b/common/commonspace/diffservice/diffservice.go index 15a9ff65..84b0d637 100644 --- a/common/commonspace/diffservice/diffservice.go +++ b/common/commonspace/diffservice/diffservice.go @@ -36,14 +36,14 @@ func NewDiffService( spaceId string, syncPeriod int, storage storage.SpaceStorage, - conf nodeconf.Configuration, + confConnector nodeconf.ConfConnector, cache cache.TreeCache, log *zap.Logger) DiffService { diff := ldiff.New(16, 16) l := log.With(zap.String("spaceId", spaceId)) factory := spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient) - syncer := newDiffSyncer(spaceId, diff, conf, cache, storage, factory, l) + syncer := newDiffSyncer(spaceId, diff, confConnector, cache, storage, factory, l) periodicSync := newPeriodicSync(syncPeriod, syncer, l) return &diffService{ diff --git a/common/commonspace/diffservice/diffsyncer.go b/common/commonspace/diffservice/diffsyncer.go index 8e354294..fe1d5d93 100644 --- a/common/commonspace/diffservice/diffsyncer.go +++ b/common/commonspace/diffservice/diffsyncer.go @@ -21,17 +21,17 @@ type DiffSyncer interface { func newDiffSyncer( spaceId string, diff ldiff.Diff, - nconf nodeconf.Configuration, + confConnector nodeconf.ConfConnector, cache cache.TreeCache, storage storage.SpaceStorage, clientFactory spacesyncproto.ClientFactory, log *zap.Logger) DiffSyncer { return &diffSyncer{ diff: diff, - nconf: nconf, spaceId: spaceId, cache: cache, storage: storage, + confConnector: confConnector, clientFactory: clientFactory, log: log, } @@ -40,7 +40,7 @@ func newDiffSyncer( type diffSyncer struct { spaceId string diff ldiff.Diff - nconf nodeconf.Configuration + confConnector nodeconf.ConfConnector cache cache.TreeCache storage storage.SpaceStorage clientFactory spacesyncproto.ClientFactory @@ -50,7 +50,7 @@ type diffSyncer struct { func (d *diffSyncer) Sync(ctx context.Context) error { st := time.Now() // diffing with responsible peers according to configuration - peers, err := d.nconf.ResponsiblePeers(ctx, d.spaceId) + peers, err := d.confConnector.GetResponsiblePeers(ctx, d.spaceId) if err != nil { return err } diff --git a/common/commonspace/diffservice/diffsyncer_test.go b/common/commonspace/diffservice/diffsyncer_test.go index 041857e3..444b73fa 100644 --- a/common/commonspace/diffservice/diffsyncer_test.go +++ b/common/commonspace/diffservice/diffsyncer_test.go @@ -88,7 +88,7 @@ func TestDiffSyncer_Sync(t *testing.T) { defer ctrl.Finish() diffMock := mock_ldiff.NewMockDiff(ctrl) - nconfMock := mock_nodeconf.NewMockConfiguration(ctrl) + connectorMock := mock_nodeconf.NewMockConfConnector(ctrl) cacheMock := mock_cache.NewMockTreeCache(ctrl) stMock := mock_storage.NewMockSpaceStorage(ctrl) clientMock := mock_spacesyncproto.NewMockDRPCSpaceClient(ctrl) @@ -97,11 +97,11 @@ func TestDiffSyncer_Sync(t *testing.T) { }) spaceId := "spaceId" l := logger.NewNamed(spaceId) - diffSyncer := newDiffSyncer(spaceId, diffMock, nconfMock, cacheMock, stMock, factory, l) + diffSyncer := newDiffSyncer(spaceId, diffMock, connectorMock, cacheMock, stMock, factory, l) t.Run("diff syncer sync simple", func(t *testing.T) { - nconfMock.EXPECT(). - ResponsiblePeers(gomock.Any(), spaceId). + connectorMock.EXPECT(). + GetResponsiblePeers(gomock.Any(), spaceId). Return([]peer.Peer{mockPeer{}}, nil) diffMock.EXPECT(). Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))). @@ -115,8 +115,8 @@ func TestDiffSyncer_Sync(t *testing.T) { }) t.Run("diff syncer sync conf error", func(t *testing.T) { - nconfMock.EXPECT(). - ResponsiblePeers(gomock.Any(), spaceId). + connectorMock.EXPECT(). + GetResponsiblePeers(gomock.Any(), spaceId). Return(nil, fmt.Errorf("some error")) require.Error(t, diffSyncer.Sync(ctx)) @@ -127,8 +127,8 @@ func TestDiffSyncer_Sync(t *testing.T) { aclRoot := &aclrecordproto.RawACLRecordWithId{} spaceHeader := &spacesyncproto.SpaceHeader{} - nconfMock.EXPECT(). - ResponsiblePeers(gomock.Any(), spaceId). + connectorMock.EXPECT(). + GetResponsiblePeers(gomock.Any(), spaceId). Return([]peer.Peer{mockPeer{}}, nil) diffMock.EXPECT(). Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))). @@ -150,8 +150,8 @@ func TestDiffSyncer_Sync(t *testing.T) { }) t.Run("diff syncer sync other error", func(t *testing.T) { - nconfMock.EXPECT(). - ResponsiblePeers(gomock.Any(), spaceId). + connectorMock.EXPECT(). + GetResponsiblePeers(gomock.Any(), spaceId). Return([]peer.Peer{mockPeer{}}, nil) diffMock.EXPECT(). Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))). diff --git a/common/commonspace/service.go b/common/commonspace/service.go index ef287659..adefcf7f 100644 --- a/common/commonspace/service.go +++ b/common/commonspace/service.go @@ -8,6 +8,7 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/config" ) @@ -32,6 +33,7 @@ type service struct { configurationService nodeconf.Service storageProvider storage.SpaceStorageProvider cache cache.TreeCache + pool pool.Pool } func (s *service) Init(a *app.App) (err error) { @@ -39,6 +41,7 @@ func (s *service) Init(a *app.App) (err error) { s.storageProvider = a.MustComponent(storage.CName).(storage.SpaceStorageProvider) s.configurationService = a.MustComponent(nodeconf.CName).(nodeconf.Service) s.cache = a.MustComponent(cache.CName).(cache.TreeCache) + s.pool = a.MustComponent(pool.CName).(pool.Pool) return nil } @@ -84,8 +87,9 @@ func (s *service) GetSpace(ctx context.Context, id string) (Space, error) { return nil, err } lastConfiguration := s.configurationService.GetLast() - diffService := diffservice.NewDiffService(id, s.config.SyncPeriod, st, lastConfiguration, s.cache, log) - syncService := syncservice.NewSyncService(id, diffService, s.cache, lastConfiguration) + confConnector := nodeconf.NewConfConnector(lastConfiguration, s.pool) + diffService := diffservice.NewDiffService(id, s.config.SyncPeriod, st, confConnector, s.cache, log) + syncService := syncservice.NewSyncService(id, diffService, s.cache, lastConfiguration, confConnector) sp := &space{ id: id, syncService: syncService, diff --git a/common/commonspace/syncservice/syncservice.go b/common/commonspace/syncservice/syncservice.go index d065832a..ae4173b2 100644 --- a/common/commonspace/syncservice/syncservice.go +++ b/common/commonspace/syncservice/syncservice.go @@ -30,37 +30,42 @@ type syncService struct { spaceId string syncClient SyncClient - configuration nodeconf.Configuration clientFactory spacesyncproto.ClientFactory streamLoopCtx context.Context stopStreamLoop context.CancelFunc + connector nodeconf.ConfConnector streamLoopDone chan struct{} } -func NewSyncService(spaceId string, headNotifiable HeadNotifiable, cache cache.TreeCache, configuration nodeconf.Configuration) SyncService { +func NewSyncService( + spaceId string, + headNotifiable HeadNotifiable, + cache cache.TreeCache, + configuration nodeconf.Configuration, + confConnector nodeconf.ConfConnector) SyncService { var syncHandler SyncHandler - pool := newStreamPool(func(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) { + streamPool := newStreamPool(func(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) { return syncHandler.HandleMessage(ctx, senderId, message) }) factory := newRequestFactory() - syncClient := newSyncClient(spaceId, pool, headNotifiable, factory, configuration) + syncClient := newSyncClient(spaceId, streamPool, headNotifiable, factory, configuration) syncHandler = newSyncHandler(spaceId, cache, syncClient) return newSyncService( spaceId, syncClient, spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient), - configuration) + confConnector) } func newSyncService( spaceId string, syncClient SyncClient, clientFactory spacesyncproto.ClientFactory, - configuration nodeconf.Configuration) *syncService { + connector nodeconf.ConfConnector) *syncService { return &syncService{ syncClient: syncClient, - configuration: configuration, + connector: connector, clientFactory: clientFactory, spaceId: spaceId, streamLoopDone: make(chan struct{}), @@ -81,7 +86,7 @@ func (s *syncService) Close() (err error) { func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) { defer close(s.streamLoopDone) checkResponsiblePeers := func() { - respPeers, err := s.configuration.ResponsiblePeers(ctx, s.spaceId) + respPeers, err := s.connector.DialResponsiblePeers(ctx, s.spaceId) if err != nil { return } diff --git a/common/nodeconf/confconnector.go b/common/nodeconf/confconnector.go new file mode 100644 index 00000000..e62be926 --- /dev/null +++ b/common/nodeconf/confconnector.go @@ -0,0 +1,54 @@ +package nodeconf + +import ( + "context" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool" +) + +type ConfConnector interface { + GetResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error) + DialResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error) +} + +type confConnector struct { + conf Configuration + pool pool.Pool +} + +func NewConfConnector(conf Configuration, pool pool.Pool) ConfConnector { + return &confConnector{conf: conf, pool: pool} +} + +func (s *confConnector) GetResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error) { + return s.dialOrConnect(ctx, spaceId, s.pool.Get, s.pool.GetOneOf) +} + +func (s *confConnector) DialResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error) { + return s.dialOrConnect(ctx, spaceId, s.pool.Dial, s.pool.DialOneOf) +} + +func (s *confConnector) dialOrConnect( + ctx context.Context, spaceId string, + connectOne func(context.Context, string) (peer.Peer, error), + connectOneOf func(context.Context, []string) (peer.Peer, error)) (peers []peer.Peer, err error) { + allNodes := s.conf.NodeIds(spaceId) + if !s.conf.IsResponsible(spaceId) { + for _, id := range allNodes { + var p peer.Peer + p, err = connectOne(ctx, id) + if err != nil { + continue + } + peers = append(peers, p) + } + } else { + var p peer.Peer + p, err = connectOneOf(ctx, allNodes) + if err != nil { + return + } + peers = []peer.Peer{p} + } + return +} diff --git a/common/nodeconf/configuration.go b/common/nodeconf/configuration.go index 8e50303b..add0647e 100644 --- a/common/nodeconf/configuration.go +++ b/common/nodeconf/configuration.go @@ -1,11 +1,7 @@ -//go:generate mockgen -destination mock_nodeconf/mock_nodeconf.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf Configuration +//go:generate mockgen -destination mock_nodeconf/mock_nodeconf.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf Configuration,ConfConnector package nodeconf import ( - "context" - "fmt" - "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer" - "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool" "github.com/anytypeio/go-chash" ) @@ -16,12 +12,6 @@ func New() Service { type Configuration interface { // Id returns current nodeconf id Id() string - // AllPeers returns all peers by spaceId except current account - AllPeers(ctx context.Context, spaceId string) (peers []peer.Peer, err error) - // OnePeer returns one of peer for spaceId - OnePeer(ctx context.Context, spaceId string) (p peer.Peer, err error) - // ResponsiblePeers returns peers for the space id that are responsible for the space - ResponsiblePeers(ctx context.Context, spaceId string) (peers []peer.Peer, err error) // NodeIds returns list of peerId for given spaceId NodeIds(spaceId string) []string // IsResponsible checks if current account responsible for given spaceId @@ -31,7 +21,6 @@ type Configuration interface { type configuration struct { id string accountId string - pool pool.Pool chash chash.CHash } @@ -39,40 +28,6 @@ func (c *configuration) Id() string { return c.id } -func (c *configuration) AllPeers(ctx context.Context, spaceId string) (peers []peer.Peer, err error) { - nodeIds := c.NodeIds(spaceId) - peers = make([]peer.Peer, 0, len(nodeIds)) - for _, id := range nodeIds { - p, e := c.pool.Get(ctx, id) - if e == nil { - peers = append(peers, p) - } - } - if len(peers) == 0 { - return nil, fmt.Errorf("unable to connect to any node") - } - return -} - -func (c *configuration) ResponsiblePeers(ctx context.Context, spaceId string) (peers []peer.Peer, err error) { - if c.IsResponsible(spaceId) { - return c.AllPeers(ctx, spaceId) - } else { - var one peer.Peer - one, err = c.OnePeer(ctx, spaceId) - if err != nil { - return - } - peers = []peer.Peer{one} - return - } -} - -func (c *configuration) OnePeer(ctx context.Context, spaceId string) (p peer.Peer, err error) { - nodeIds := c.NodeIds(spaceId) - return c.pool.GetOneOf(ctx, nodeIds) -} - func (c *configuration) NodeIds(spaceId string) []string { members := c.chash.GetMembers(spaceId) res := make([]string, 0, len(members)) diff --git a/common/nodeconf/mock_nodeconf/mock_nodeconf.go b/common/nodeconf/mock_nodeconf/mock_nodeconf.go index e65895eb..a22e4a6e 100644 --- a/common/nodeconf/mock_nodeconf/mock_nodeconf.go +++ b/common/nodeconf/mock_nodeconf/mock_nodeconf.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf (interfaces: Configuration) +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf (interfaces: Configuration,ConfConnector) // Package mock_nodeconf is a generated GoMock package. package mock_nodeconf @@ -35,21 +35,6 @@ func (m *MockConfiguration) EXPECT() *MockConfigurationMockRecorder { return m.recorder } -// AllPeers mocks base method. -func (m *MockConfiguration) AllPeers(arg0 context.Context, arg1 string) ([]peer.Peer, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AllPeers", arg0, arg1) - ret0, _ := ret[0].([]peer.Peer) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AllPeers indicates an expected call of AllPeers. -func (mr *MockConfigurationMockRecorder) AllPeers(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllPeers", reflect.TypeOf((*MockConfiguration)(nil).AllPeers), arg0, arg1) -} - // Id mocks base method. func (m *MockConfiguration) Id() string { m.ctrl.T.Helper() @@ -92,32 +77,55 @@ func (mr *MockConfigurationMockRecorder) NodeIds(arg0 interface{}) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeIds", reflect.TypeOf((*MockConfiguration)(nil).NodeIds), arg0) } -// OnePeer mocks base method. -func (m *MockConfiguration) OnePeer(arg0 context.Context, arg1 string) (peer.Peer, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnePeer", arg0, arg1) - ret0, _ := ret[0].(peer.Peer) - ret1, _ := ret[1].(error) - return ret0, ret1 +// MockConfConnector is a mock of ConfConnector interface. +type MockConfConnector struct { + ctrl *gomock.Controller + recorder *MockConfConnectorMockRecorder } -// OnePeer indicates an expected call of OnePeer. -func (mr *MockConfigurationMockRecorder) OnePeer(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnePeer", reflect.TypeOf((*MockConfiguration)(nil).OnePeer), arg0, arg1) +// MockConfConnectorMockRecorder is the mock recorder for MockConfConnector. +type MockConfConnectorMockRecorder struct { + mock *MockConfConnector } -// ResponsiblePeers mocks base method. -func (m *MockConfiguration) ResponsiblePeers(arg0 context.Context, arg1 string) ([]peer.Peer, error) { +// NewMockConfConnector creates a new mock instance. +func NewMockConfConnector(ctrl *gomock.Controller) *MockConfConnector { + mock := &MockConfConnector{ctrl: ctrl} + mock.recorder = &MockConfConnectorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockConfConnector) EXPECT() *MockConfConnectorMockRecorder { + return m.recorder +} + +// DialResponsiblePeers mocks base method. +func (m *MockConfConnector) DialResponsiblePeers(arg0 context.Context, arg1 string) ([]peer.Peer, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ResponsiblePeers", arg0, arg1) + ret := m.ctrl.Call(m, "DialResponsiblePeers", arg0, arg1) ret0, _ := ret[0].([]peer.Peer) ret1, _ := ret[1].(error) return ret0, ret1 } -// ResponsiblePeers indicates an expected call of ResponsiblePeers. -func (mr *MockConfigurationMockRecorder) ResponsiblePeers(arg0, arg1 interface{}) *gomock.Call { +// DialResponsiblePeers indicates an expected call of DialResponsiblePeers. +func (mr *MockConfConnectorMockRecorder) DialResponsiblePeers(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResponsiblePeers", reflect.TypeOf((*MockConfiguration)(nil).ResponsiblePeers), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DialResponsiblePeers", reflect.TypeOf((*MockConfConnector)(nil).DialResponsiblePeers), arg0, arg1) +} + +// GetResponsiblePeers mocks base method. +func (m *MockConfConnector) GetResponsiblePeers(arg0 context.Context, arg1 string) ([]peer.Peer, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetResponsiblePeers", arg0, arg1) + ret0, _ := ret[0].([]peer.Peer) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetResponsiblePeers indicates an expected call of GetResponsiblePeers. +func (mr *MockConfConnectorMockRecorder) GetResponsiblePeers(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResponsiblePeers", reflect.TypeOf((*MockConfConnector)(nil).GetResponsiblePeers), arg0, arg1) } diff --git a/common/nodeconf/service.go b/common/nodeconf/service.go index cc80e288..66f6b6b3 100644 --- a/common/nodeconf/service.go +++ b/common/nodeconf/service.go @@ -3,7 +3,6 @@ package nodeconf import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/app" "github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger" - "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool" "github.com/anytypeio/go-anytype-infrastructure-experiments/config" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/encryptionkey" @@ -29,7 +28,6 @@ type Service interface { type service struct { accountId string - pool pool.Pool consensusPeers []string last Configuration @@ -53,12 +51,10 @@ func (n *Node) Capacity() float64 { func (s *service) Init(a *app.App) (err error) { conf := a.MustComponent(config.CName).(*config.Config) s.accountId = conf.Account.PeerId - s.pool = a.MustComponent(pool.CName).(pool.Pool) config := &configuration{ id: "config", accountId: s.accountId, - pool: s.pool, } if config.chash, err = chash.New(chash.Config{ PartitionCount: partitionCount, diff --git a/go.mod b/go.mod index 48d2d5c4..c25e1b35 100644 --- a/go.mod +++ b/go.mod @@ -61,9 +61,12 @@ require ( go.uber.org/multierr v1.8.0 // indirect golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect golang.org/x/image v0.0.0-20200119044424-58c23975cae1 // indirect + golang.org/x/mod v0.4.2 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.5 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect lukechampine.com/blake3 v1.1.6 // indirect diff --git a/go.sum b/go.sum index cf56905e..6805b56c 100644 --- a/go.sum +++ b/go.sum @@ -167,6 +167,7 @@ golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+o golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -207,6 +208,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From c3d8273caad15a2d7fd1107143971a675e2e0a17 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Mon, 10 Oct 2022 09:10:47 +0200 Subject: [PATCH 17/17] SyncTree tests --- common/commonspace/synctree/synctree.go | 14 +- common/commonspace/synctree/synctree_test.go | 176 ++++++++++++++++++ .../mock_updatelistener.go | 59 ++++++ .../synctree/updatelistener/updatelistener.go | 1 + 4 files changed, 245 insertions(+), 5 deletions(-) create mode 100644 common/commonspace/synctree/synctree_test.go create mode 100644 common/commonspace/synctree/updatelistener/mock_updatelistener/mock_updatelistener.go diff --git a/common/commonspace/synctree/synctree.go b/common/commonspace/synctree/synctree.go index 99c6014d..14e05a3e 100644 --- a/common/commonspace/synctree/synctree.go +++ b/common/commonspace/synctree/synctree.go @@ -17,6 +17,10 @@ type SyncTree struct { listener updatelistener.UpdateListener } +var createDerivedObjectTree = tree.CreateDerivedObjectTree +var createObjectTree = tree.CreateObjectTree +var buildObjectTree = tree.BuildObjectTree + func DeriveSyncTree( ctx context.Context, payload tree.ObjectTreeCreatePayload, @@ -24,7 +28,7 @@ func DeriveSyncTree( listener updatelistener.UpdateListener, aclList list.ACLList, createStorage storage.TreeStorageCreatorFunc) (t tree.ObjectTree, err error) { - t, err = tree.CreateDerivedObjectTree(payload, aclList, createStorage) + t, err = createDerivedObjectTree(payload, aclList, createStorage) if err != nil { return } @@ -46,7 +50,7 @@ func CreateSyncTree( listener updatelistener.UpdateListener, aclList list.ACLList, createStorage storage.TreeStorageCreatorFunc) (t tree.ObjectTree, err error) { - t, err = tree.CreateObjectTree(payload, aclList, createStorage) + t, err = createObjectTree(payload, aclList, createStorage) if err != nil { return } @@ -76,7 +80,7 @@ func buildSyncTree( treeStorage storage.TreeStorage, listener updatelistener.UpdateListener, aclList list.ACLList) (t tree.ObjectTree, err error) { - t, err = tree.BuildObjectTree(treeStorage, aclList) + t, err = buildObjectTree(treeStorage, aclList) if err != nil { return } @@ -93,7 +97,7 @@ func buildSyncTree( } func (s *SyncTree) AddContent(ctx context.Context, content tree.SignableChangeContent) (res tree.AddResult, err error) { - res, err = s.AddContent(ctx, content) + res, err = s.ObjectTree.AddContent(ctx, content) if err != nil { return } @@ -103,7 +107,7 @@ func (s *SyncTree) AddContent(ctx context.Context, content tree.SignableChangeCo } func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (res tree.AddResult, err error) { - res, err = s.AddRawChanges(ctx, changes...) + res, err = s.ObjectTree.AddRawChanges(ctx, changes...) if err != nil { return } diff --git a/common/commonspace/synctree/synctree_test.go b/common/commonspace/synctree/synctree_test.go new file mode 100644 index 00000000..ef1bd99f --- /dev/null +++ b/common/commonspace/synctree/synctree_test.go @@ -0,0 +1,176 @@ +package synctree + +import ( + "context" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/mock_syncservice" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener/mock_updatelistener" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list/mock_list" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage/mock_storage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree" + mock_tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree/mock_objecttree" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + "testing" +) + +type syncTreeMatcher struct { + objTree tree.ObjectTree + client syncservice.SyncClient + listener updatelistener.UpdateListener +} + +func (s syncTreeMatcher) Matches(x interface{}) bool { + t, ok := x.(*SyncTree) + if !ok { + return false + } + return s.objTree == t.ObjectTree && t.syncClient == s.client && t.listener == s.listener +} + +func (s syncTreeMatcher) String() string { + return "" +} + +func Test_DeriveSyncTree(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl) + syncClientMock := mock_syncservice.NewMockSyncClient(ctrl) + aclListMock := mock_list.NewMockACLList(ctrl) + createStorage := storage.TreeStorageCreatorFunc(func(payload storage.TreeStorageCreatePayload) (storage.TreeStorage, error) { + return nil, nil + }) + objTreeMock := mock_tree.NewMockObjectTree(ctrl) + createDerivedObjectTree = func(payload tree.ObjectTreeCreatePayload, l list.ACLList, create storage.TreeStorageCreatorFunc) (objTree tree.ObjectTree, err error) { + require.Equal(t, l, aclListMock) + return objTreeMock, nil + } + headUpdate := &spacesyncproto.ObjectSyncMessage{} + syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate) + syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil) + + _, err := DeriveSyncTree(ctx, tree.ObjectTreeCreatePayload{}, syncClientMock, updateListenerMock, aclListMock, createStorage) + require.NoError(t, err) +} + +func Test_CreateSyncTree(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl) + syncClientMock := mock_syncservice.NewMockSyncClient(ctrl) + aclListMock := mock_list.NewMockACLList(ctrl) + createStorage := storage.TreeStorageCreatorFunc(func(payload storage.TreeStorageCreatePayload) (storage.TreeStorage, error) { + return nil, nil + }) + objTreeMock := mock_tree.NewMockObjectTree(ctrl) + createObjectTree = func(payload tree.ObjectTreeCreatePayload, l list.ACLList, create storage.TreeStorageCreatorFunc) (objTree tree.ObjectTree, err error) { + require.Equal(t, l, aclListMock) + return objTreeMock, nil + } + headUpdate := &spacesyncproto.ObjectSyncMessage{} + syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate) + syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil) + + _, err := CreateSyncTree(ctx, tree.ObjectTreeCreatePayload{}, syncClientMock, updateListenerMock, aclListMock, createStorage) + require.NoError(t, err) +} + +func Test_BuildSyncTree(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl) + syncClientMock := mock_syncservice.NewMockSyncClient(ctrl) + aclListMock := mock_list.NewMockACLList(ctrl) + storageMock := mock_storage.NewMockTreeStorage(ctrl) + objTreeMock := mock_tree.NewMockObjectTree(ctrl) + buildObjectTree = func(store storage.TreeStorage, l list.ACLList) (objTree tree.ObjectTree, err error) { + require.Equal(t, aclListMock, l) + require.Equal(t, store, storageMock) + return objTreeMock, nil + } + headUpdate := &spacesyncproto.ObjectSyncMessage{} + syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate) + syncClientMock.EXPECT().BroadcastAsyncOrSendResponsible(gomock.Eq(headUpdate)).Return(nil) + + tr, err := BuildSyncTree(ctx, syncClientMock, storageMock, updateListenerMock, aclListMock) + require.NoError(t, err) + + t.Run("AddRawChanges update", func(t *testing.T) { + changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}} + expectedRes := tree.AddResult{ + Added: changes, + Mode: tree.Append, + } + objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)). + Return(expectedRes, nil) + updateListenerMock.EXPECT().Update(tr) + + syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate) + syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil) + res, err := tr.AddRawChanges(ctx, changes...) + require.NoError(t, err) + require.Equal(t, expectedRes, res) + }) + + t.Run("AddRawChanges rebuild", func(t *testing.T) { + changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}} + expectedRes := tree.AddResult{ + Added: changes, + Mode: tree.Rebuild, + } + objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)). + Return(expectedRes, nil) + updateListenerMock.EXPECT().Rebuild(tr) + + syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate) + syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil) + res, err := tr.AddRawChanges(ctx, changes...) + require.NoError(t, err) + require.Equal(t, expectedRes, res) + }) + + t.Run("AddRawChanges nothing", func(t *testing.T) { + changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}} + expectedRes := tree.AddResult{ + Added: changes, + Mode: tree.Nothing, + } + objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)). + Return(expectedRes, nil) + + res, err := tr.AddRawChanges(ctx, changes...) + require.NoError(t, err) + require.Equal(t, expectedRes, res) + }) + + t.Run("AddContent", func(t *testing.T) { + changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}} + content := tree.SignableChangeContent{ + Data: []byte("abcde"), + } + expectedRes := tree.AddResult{ + Mode: tree.Append, + Added: changes, + } + objTreeMock.EXPECT().AddContent(gomock.Any(), gomock.Eq(content)). + Return(expectedRes, nil) + + syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate) + syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil) + res, err := tr.AddContent(ctx, content) + require.NoError(t, err) + require.Equal(t, expectedRes, res) + }) +} diff --git a/common/commonspace/synctree/updatelistener/mock_updatelistener/mock_updatelistener.go b/common/commonspace/synctree/updatelistener/mock_updatelistener/mock_updatelistener.go new file mode 100644 index 00000000..cb88dd6a --- /dev/null +++ b/common/commonspace/synctree/updatelistener/mock_updatelistener/mock_updatelistener.go @@ -0,0 +1,59 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener (interfaces: UpdateListener) + +// Package mock_updatelistener is a generated GoMock package. +package mock_updatelistener + +import ( + reflect "reflect" + + tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree" + gomock "github.com/golang/mock/gomock" +) + +// MockUpdateListener is a mock of UpdateListener interface. +type MockUpdateListener struct { + ctrl *gomock.Controller + recorder *MockUpdateListenerMockRecorder +} + +// MockUpdateListenerMockRecorder is the mock recorder for MockUpdateListener. +type MockUpdateListenerMockRecorder struct { + mock *MockUpdateListener +} + +// NewMockUpdateListener creates a new mock instance. +func NewMockUpdateListener(ctrl *gomock.Controller) *MockUpdateListener { + mock := &MockUpdateListener{ctrl: ctrl} + mock.recorder = &MockUpdateListenerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockUpdateListener) EXPECT() *MockUpdateListenerMockRecorder { + return m.recorder +} + +// Rebuild mocks base method. +func (m *MockUpdateListener) Rebuild(arg0 tree.ObjectTree) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Rebuild", arg0) +} + +// Rebuild indicates an expected call of Rebuild. +func (mr *MockUpdateListenerMockRecorder) Rebuild(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Rebuild", reflect.TypeOf((*MockUpdateListener)(nil).Rebuild), arg0) +} + +// Update mocks base method. +func (m *MockUpdateListener) Update(arg0 tree.ObjectTree) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Update", arg0) +} + +// Update indicates an expected call of Update. +func (mr *MockUpdateListenerMockRecorder) Update(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockUpdateListener)(nil).Update), arg0) +} diff --git a/common/commonspace/synctree/updatelistener/updatelistener.go b/common/commonspace/synctree/updatelistener/updatelistener.go index 0a1a6659..49f6e0d5 100644 --- a/common/commonspace/synctree/updatelistener/updatelistener.go +++ b/common/commonspace/synctree/updatelistener/updatelistener.go @@ -1,3 +1,4 @@ +//go:generate mockgen -destination mock_updatelistener/mock_updatelistener.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener UpdateListener package updatelistener import "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"