mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-08 05:57:03 +09:00
Fix commonspace tests
This commit is contained in:
parent
daefdae641
commit
4de44b020a
6 changed files with 357 additions and 343 deletions
|
@ -1,268 +1,224 @@
|
|||
package commonspace
|
||||
|
||||
//
|
||||
//func addIncorrectSnapshot(settingsObject settings.SettingsObject, acc *accountdata.AccountKeys, partialIds map[string]struct{}, newId string) (err error) {
|
||||
// factory := settingsstate.NewChangeFactory()
|
||||
// bytes, err := factory.CreateObjectDeleteChange(newId, &settingsstate.State{DeletedIds: partialIds}, true)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// ch, err := settingsObject.PrepareChange(objecttree.SignableChangeContent{
|
||||
// Data: bytes,
|
||||
// Key: acc.SignKey,
|
||||
// IsSnapshot: true,
|
||||
// IsEncrypted: false,
|
||||
// Timestamp: time.Now().Unix(),
|
||||
// })
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// res, err := settingsObject.AddRawChanges(context.Background(), objecttree.RawChangesPayload{
|
||||
// NewHeads: []string{ch.Id},
|
||||
// RawChanges: []*treechangeproto.RawTreeChangeWithId{ch},
|
||||
// })
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// if res.Mode != objecttree.Rebuild {
|
||||
// return fmt.Errorf("incorrect mode: %d", res.Mode)
|
||||
// }
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//func TestSpaceDeleteIds(t *testing.T) {
|
||||
// fx := newFixture(t)
|
||||
// acc := fx.account.Account()
|
||||
// rk := crypto.NewAES()
|
||||
// privKey, _, _ := crypto.GenerateRandomEd25519KeyPair()
|
||||
// ctx := context.Background()
|
||||
// totalObjs := 1500
|
||||
//
|
||||
// // creating space
|
||||
// sp, err := fx.spaceService.CreateSpace(ctx, SpaceCreatePayload{
|
||||
// SigningKey: acc.SignKey,
|
||||
// SpaceType: "type",
|
||||
// ReadKey: rk,
|
||||
// MetadataKey: privKey,
|
||||
// ReplicationKey: 10,
|
||||
// MasterKey: acc.PeerKey,
|
||||
// })
|
||||
// require.NoError(t, err)
|
||||
// require.NotNil(t, sp)
|
||||
//
|
||||
// // initializing space
|
||||
// spc, err := fx.spaceService.NewSpace(ctx, sp, Deps{TreeSyncer: mockTreeSyncer{}, SyncStatus: syncstatus.NewNoOpSyncStatus()})
|
||||
// require.NoError(t, err)
|
||||
// require.NotNil(t, spc)
|
||||
// // adding space to tree manager
|
||||
// fx.treeManager.space = spc
|
||||
// err = spc.Init(ctx)
|
||||
// require.NoError(t, err)
|
||||
// close(fx.treeManager.waitLoad)
|
||||
//
|
||||
// var ids []string
|
||||
// for i := 0; i < totalObjs; i++ {
|
||||
// // creating a tree
|
||||
// bytes := make([]byte, 32)
|
||||
// rand.Read(bytes)
|
||||
// doc, err := spc.TreeBuilder().CreateTree(ctx, objecttree.ObjectTreeCreatePayload{
|
||||
// PrivKey: acc.SignKey,
|
||||
// ChangeType: "some",
|
||||
// SpaceId: spc.Id(),
|
||||
// IsEncrypted: false,
|
||||
// Seed: bytes,
|
||||
// Timestamp: time.Now().Unix(),
|
||||
// })
|
||||
// require.NoError(t, err)
|
||||
// tr, err := spc.TreeBuilder().PutTree(ctx, doc, nil)
|
||||
// require.NoError(t, err)
|
||||
// ids = append(ids, tr.Id())
|
||||
// tr.Close()
|
||||
// }
|
||||
// // deleting trees
|
||||
// for _, id := range ids {
|
||||
// err = spc.DeleteTree(ctx, id)
|
||||
// require.NoError(t, err)
|
||||
// }
|
||||
// time.Sleep(3 * time.Second)
|
||||
// spc.Close()
|
||||
// require.Equal(t, len(ids), len(fx.treeManager.deletedIds))
|
||||
//}
|
||||
//
|
||||
//func createTree(t *testing.T, ctx context.Context, spc Space, acc *accountdata.AccountKeys) string {
|
||||
// bytes := make([]byte, 32)
|
||||
// rand.Read(bytes)
|
||||
// doc, err := spc.TreeBuilder().CreateTree(ctx, objecttree.ObjectTreeCreatePayload{
|
||||
// PrivKey: acc.SignKey,
|
||||
// ChangeType: "some",
|
||||
// SpaceId: spc.Id(),
|
||||
// IsEncrypted: false,
|
||||
// Seed: bytes,
|
||||
// Timestamp: time.Now().Unix(),
|
||||
// })
|
||||
// require.NoError(t, err)
|
||||
// tr, err := spc.TreeBuilder().PutTree(ctx, doc, nil)
|
||||
// require.NoError(t, err)
|
||||
// tr.Close()
|
||||
// return tr.Id()
|
||||
//}
|
||||
//
|
||||
//func TestSpaceDeleteIdsIncorrectSnapshot(t *testing.T) {
|
||||
// fx := newFixture(t)
|
||||
// acc := fx.account.Account()
|
||||
// rk := crypto.NewAES()
|
||||
// privKey, _, _ := crypto.GenerateRandomEd25519KeyPair()
|
||||
// ctx := context.Background()
|
||||
// totalObjs := 1500
|
||||
// partialObjs := 300
|
||||
//
|
||||
// // creating space
|
||||
// sp, err := fx.spaceService.CreateSpace(ctx, SpaceCreatePayload{
|
||||
// SigningKey: acc.SignKey,
|
||||
// SpaceType: "type",
|
||||
// ReadKey: rk,
|
||||
// MetadataKey: privKey,
|
||||
// ReplicationKey: 10,
|
||||
// MasterKey: acc.PeerKey,
|
||||
// })
|
||||
// require.NoError(t, err)
|
||||
// require.NotNil(t, sp)
|
||||
//
|
||||
// // initializing space
|
||||
// spc, err := fx.spaceService.NewSpace(ctx, sp, Deps{TreeSyncer: mockTreeSyncer{}, SyncStatus: syncstatus.NewNoOpSyncStatus()})
|
||||
// require.NoError(t, err)
|
||||
// require.NotNil(t, spc)
|
||||
// // adding space to tree manager
|
||||
// fx.treeManager.space = spc
|
||||
// err = spc.Init(ctx)
|
||||
// close(fx.treeManager.waitLoad)
|
||||
// require.NoError(t, err)
|
||||
//
|
||||
// settingsObject := spc.(*space).app.MustComponent(settings.CName).(settings.Settings).SettingsObject()
|
||||
// var ids []string
|
||||
// for i := 0; i < totalObjs; i++ {
|
||||
// id := createTree(t, ctx, spc, acc)
|
||||
// ids = append(ids, id)
|
||||
// }
|
||||
// // copying storage, so we will have all the trees locally
|
||||
// inmemory := spc.Storage().(*spacestorage.InMemorySpaceStorage)
|
||||
// storageCopy := inmemory.CopyStorage()
|
||||
// treesCopy := inmemory.AllTrees()
|
||||
//
|
||||
// // deleting trees
|
||||
// for _, id := range ids {
|
||||
// err = spc.DeleteTree(ctx, id)
|
||||
// require.NoError(t, err)
|
||||
// }
|
||||
// mapIds := map[string]struct{}{}
|
||||
// for _, id := range ids[:partialObjs] {
|
||||
// mapIds[id] = struct{}{}
|
||||
// }
|
||||
// // adding snapshot that breaks the state
|
||||
// err = addIncorrectSnapshot(settingsObject, acc, mapIds, ids[partialObjs])
|
||||
// require.NoError(t, err)
|
||||
// // copying the contents of the settings tree
|
||||
// treesCopy[settingsObject.Id()] = settingsObject.Storage()
|
||||
// storageCopy.SetTrees(treesCopy)
|
||||
// spc.Close()
|
||||
// time.Sleep(100 * time.Millisecond)
|
||||
// // now we replace the storage, so the trees are back, but the settings object says that they are deleted
|
||||
// fx.storageProvider.(*spacestorage.InMemorySpaceStorageProvider).SetStorage(storageCopy)
|
||||
//
|
||||
// spc, err = fx.spaceService.NewSpace(ctx, sp, Deps{TreeSyncer: mockTreeSyncer{}, SyncStatus: syncstatus.NewNoOpSyncStatus()})
|
||||
// require.NoError(t, err)
|
||||
// require.NotNil(t, spc)
|
||||
// fx.treeManager.waitLoad = make(chan struct{})
|
||||
// fx.treeManager.space = spc
|
||||
// fx.treeManager.deletedIds = nil
|
||||
// fx.treeManager.wait = true
|
||||
// err = spc.Init(ctx)
|
||||
// require.NoError(t, err)
|
||||
// close(fx.treeManager.waitLoad)
|
||||
//
|
||||
// // waiting until everything is deleted
|
||||
// time.Sleep(3 * time.Second)
|
||||
// require.Equal(t, len(ids), len(fx.treeManager.deletedIds))
|
||||
//
|
||||
// // checking that new snapshot will contain all the changes
|
||||
// settingsObject = spc.(*space).app.MustComponent(settings.CName).(settings.Settings).SettingsObject()
|
||||
// settings.DoSnapshot = func(treeLen int) bool {
|
||||
// return true
|
||||
// }
|
||||
// id := createTree(t, ctx, spc, acc)
|
||||
// err = spc.DeleteTree(ctx, id)
|
||||
// require.NoError(t, err)
|
||||
// delIds := settingsObject.Root().Model.(*spacesyncproto.SettingsData).Snapshot.DeletedIds
|
||||
// require.Equal(t, totalObjs+1, len(delIds))
|
||||
//}
|
||||
//
|
||||
//func TestSpaceDeleteIdsMarkDeleted(t *testing.T) {
|
||||
// fx := newFixture(t)
|
||||
// acc := fx.account.Account()
|
||||
// rk := crypto.NewAES()
|
||||
// privKey, _, _ := crypto.GenerateRandomEd25519KeyPair()
|
||||
// ctx := context.Background()
|
||||
// totalObjs := 1500
|
||||
//
|
||||
// // creating space
|
||||
// sp, err := fx.spaceService.CreateSpace(ctx, SpaceCreatePayload{
|
||||
// SigningKey: acc.SignKey,
|
||||
// SpaceType: "type",
|
||||
// ReadKey: rk,
|
||||
// MetadataKey: privKey,
|
||||
// ReplicationKey: 10,
|
||||
// MasterKey: acc.PeerKey,
|
||||
// })
|
||||
// require.NoError(t, err)
|
||||
// require.NotNil(t, sp)
|
||||
//
|
||||
// // initializing space
|
||||
// spc, err := fx.spaceService.NewSpace(ctx, sp, Deps{TreeSyncer: mockTreeSyncer{}, SyncStatus: syncstatus.NewNoOpSyncStatus()})
|
||||
// require.NoError(t, err)
|
||||
// require.NotNil(t, spc)
|
||||
// // adding space to tree manager
|
||||
// fx.treeManager.space = spc
|
||||
// err = spc.Init(ctx)
|
||||
// require.NoError(t, err)
|
||||
// close(fx.treeManager.waitLoad)
|
||||
//
|
||||
// settingsObject := spc.(*space).app.MustComponent(settings.CName).(settings.Settings).SettingsObject()
|
||||
// var ids []string
|
||||
// for i := 0; i < totalObjs; i++ {
|
||||
// id := createTree(t, ctx, spc, acc)
|
||||
// ids = append(ids, id)
|
||||
// }
|
||||
// // copying storage, so we will have the same contents, except for empty trees
|
||||
// inmemory := spc.Storage().(*spacestorage.InMemorySpaceStorage)
|
||||
// storageCopy := inmemory.CopyStorage()
|
||||
//
|
||||
// // deleting trees, this will prepare the document to have all the deletion changes
|
||||
// for _, id := range ids {
|
||||
// err = spc.DeleteTree(ctx, id)
|
||||
// require.NoError(t, err)
|
||||
// }
|
||||
// treesMap := map[string]treestorage.TreeStorage{}
|
||||
// // copying the contents of the settings tree
|
||||
// treesMap[settingsObject.Id()] = settingsObject.Storage()
|
||||
// storageCopy.SetTrees(treesMap)
|
||||
// spc.Close()
|
||||
// time.Sleep(100 * time.Millisecond)
|
||||
// // now we replace the storage, so the trees are back, but the settings object says that they are deleted
|
||||
// fx.storageProvider.(*spacestorage.InMemorySpaceStorageProvider).SetStorage(storageCopy)
|
||||
//
|
||||
// spc, err = fx.spaceService.NewSpace(ctx, sp, Deps{TreeSyncer: mockTreeSyncer{}, SyncStatus: syncstatus.NewNoOpSyncStatus()})
|
||||
// require.NoError(t, err)
|
||||
// require.NotNil(t, spc)
|
||||
// fx.treeManager.space = spc
|
||||
// fx.treeManager.waitLoad = make(chan struct{})
|
||||
// fx.treeManager.deletedIds = nil
|
||||
// fx.treeManager.markedIds = nil
|
||||
// err = spc.Init(ctx)
|
||||
// require.NoError(t, err)
|
||||
// close(fx.treeManager.waitLoad)
|
||||
//
|
||||
// // waiting until everything is deleted
|
||||
// time.Sleep(3 * time.Second)
|
||||
// require.Equal(t, len(ids), len(fx.treeManager.markedIds))
|
||||
// require.Zero(t, len(fx.treeManager.deletedIds))
|
||||
//}
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
anystore "github.com/anyproto/any-store"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anyproto/any-sync/commonspace/object/accountdata"
|
||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
||||
"github.com/anyproto/any-sync/commonspace/spacestorage"
|
||||
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||
"github.com/anyproto/any-sync/util/crypto"
|
||||
)
|
||||
|
||||
func createTree(t *testing.T, ctx context.Context, spc Space, acc *accountdata.AccountKeys) string {
|
||||
bytes := make([]byte, 32)
|
||||
rand.Read(bytes)
|
||||
doc, err := spc.TreeBuilder().CreateTree(ctx, objecttree.ObjectTreeCreatePayload{
|
||||
PrivKey: acc.SignKey,
|
||||
ChangeType: "some",
|
||||
SpaceId: spc.Id(),
|
||||
IsEncrypted: false,
|
||||
Seed: bytes,
|
||||
Timestamp: time.Now().Unix(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
tr, err := spc.TreeBuilder().PutTree(ctx, doc, nil)
|
||||
require.NoError(t, err)
|
||||
tr.Close()
|
||||
return tr.Id()
|
||||
}
|
||||
|
||||
type storeSetter interface {
|
||||
SetStore(id string, store anystore.DB)
|
||||
}
|
||||
|
||||
func TestSpaceDeleteIdsMarkDeleted(t *testing.T) {
|
||||
fx := newFixture(t)
|
||||
acc := fx.account.Account()
|
||||
rk := crypto.NewAES()
|
||||
privKey, _, _ := crypto.GenerateRandomEd25519KeyPair()
|
||||
ctx := context.Background()
|
||||
totalObjs := 1000
|
||||
|
||||
// creating space
|
||||
sp, err := fx.spaceService.CreateSpace(ctx, SpaceCreatePayload{
|
||||
SigningKey: acc.SignKey,
|
||||
SpaceType: "type",
|
||||
ReadKey: rk,
|
||||
MetadataKey: privKey,
|
||||
ReplicationKey: 10,
|
||||
MasterKey: acc.PeerKey,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, sp)
|
||||
|
||||
// initializing space
|
||||
spc, err := fx.spaceService.NewSpace(ctx, sp, Deps{TreeSyncer: mockTreeSyncer{}, SyncStatus: syncstatus.NewNoOpSyncStatus()})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, spc)
|
||||
// adding space to tree manager
|
||||
fx.treeManager.space = spc
|
||||
err = spc.Init(ctx)
|
||||
require.NoError(t, err)
|
||||
close(fx.treeManager.waitLoad)
|
||||
|
||||
anyStore := spc.Storage().AnyStore()
|
||||
newStore := objecttree.CopyStore(ctx, t, anyStore.(objecttree.TestStore), "store")
|
||||
|
||||
var ids []string
|
||||
for i := 0; i < totalObjs; i++ {
|
||||
id := createTree(t, ctx, spc, acc)
|
||||
ids = append(ids, id)
|
||||
}
|
||||
// deleting trees, this will prepare the document to have all the deletion changes
|
||||
for _, id := range ids {
|
||||
err = spc.DeleteTree(ctx, id)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
settingsId := spc.Storage().StateStorage().SettingsId()
|
||||
settingsStorage, err := spc.Storage().TreeStorage(ctx, settingsId)
|
||||
require.NoError(t, err)
|
||||
var allChanges []objecttree.StorageChange
|
||||
err = settingsStorage.GetAfterOrder(ctx, "", func(ctx context.Context, change objecttree.StorageChange) (shouldContinue bool, err error) {
|
||||
rawCh := make([]byte, len(change.RawChange))
|
||||
copy(rawCh, change.RawChange)
|
||||
change.RawChange = rawCh
|
||||
allChanges = append(allChanges, change)
|
||||
return true, nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
heads, err := settingsStorage.Heads(ctx)
|
||||
require.NoError(t, err)
|
||||
commonSnapshot, err := settingsStorage.CommonSnapshot(ctx)
|
||||
require.NoError(t, err)
|
||||
newStorage, err := spacestorage.New(ctx, spc.Id(), newStore)
|
||||
require.NoError(t, err)
|
||||
newSettingsStorage, err := newStorage.TreeStorage(ctx, settingsId)
|
||||
require.NoError(t, err)
|
||||
err = newSettingsStorage.AddAllNoError(ctx, allChanges, heads, commonSnapshot)
|
||||
require.NoError(t, err)
|
||||
err = spc.Close()
|
||||
require.NoError(t, err)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
storeSetter := fx.storageProvider.(storeSetter)
|
||||
storeSetter.SetStore(sp, newStore)
|
||||
spc, err = fx.spaceService.NewSpace(ctx, sp, Deps{TreeSyncer: mockTreeSyncer{}, SyncStatus: syncstatus.NewNoOpSyncStatus()})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, spc)
|
||||
waitTest := make(chan struct{})
|
||||
fx.treeManager.wait = true
|
||||
fx.treeManager.space = spc
|
||||
fx.treeManager.condFunc = func() {
|
||||
if len(fx.treeManager.markedIds) == len(ids) {
|
||||
close(waitTest)
|
||||
}
|
||||
}
|
||||
fx.treeManager.waitLoad = make(chan struct{})
|
||||
fx.treeManager.deletedIds = nil
|
||||
fx.treeManager.markedIds = nil
|
||||
err = spc.Init(ctx)
|
||||
require.NoError(t, err)
|
||||
close(fx.treeManager.waitLoad)
|
||||
|
||||
<-waitTest
|
||||
require.Equal(t, len(ids), len(fx.treeManager.markedIds))
|
||||
require.Zero(t, len(fx.treeManager.deletedIds))
|
||||
}
|
||||
|
||||
func TestSpaceDeleteIds(t *testing.T) {
|
||||
fx := newFixture(t)
|
||||
acc := fx.account.Account()
|
||||
rk := crypto.NewAES()
|
||||
privKey, _, _ := crypto.GenerateRandomEd25519KeyPair()
|
||||
ctx := context.Background()
|
||||
totalObjs := 1000
|
||||
|
||||
// creating space
|
||||
sp, err := fx.spaceService.CreateSpace(ctx, SpaceCreatePayload{
|
||||
SigningKey: acc.SignKey,
|
||||
SpaceType: "type",
|
||||
ReadKey: rk,
|
||||
MetadataKey: privKey,
|
||||
ReplicationKey: 10,
|
||||
MasterKey: acc.PeerKey,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, sp)
|
||||
|
||||
// initializing space
|
||||
spc, err := fx.spaceService.NewSpace(ctx, sp, Deps{TreeSyncer: mockTreeSyncer{}, SyncStatus: syncstatus.NewNoOpSyncStatus()})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, spc)
|
||||
// adding space to tree manager
|
||||
fx.treeManager.space = spc
|
||||
err = spc.Init(ctx)
|
||||
require.NoError(t, err)
|
||||
close(fx.treeManager.waitLoad)
|
||||
|
||||
var ids []string
|
||||
for i := 0; i < totalObjs; i++ {
|
||||
id := createTree(t, ctx, spc, acc)
|
||||
ids = append(ids, id)
|
||||
}
|
||||
// copying storage, so we will have the same contents, except for empty trees
|
||||
anyStore := spc.Storage().AnyStore()
|
||||
newStore := objecttree.CopyStore(ctx, t, anyStore.(objecttree.TestStore), "store")
|
||||
// deleting trees, this will prepare the document to have all the deletion changes
|
||||
for _, id := range ids {
|
||||
err = spc.DeleteTree(ctx, id)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
settingsId := spc.Storage().StateStorage().SettingsId()
|
||||
settingsStorage, err := spc.Storage().TreeStorage(ctx, settingsId)
|
||||
require.NoError(t, err)
|
||||
var allChanges []objecttree.StorageChange
|
||||
err = settingsStorage.GetAfterOrder(ctx, "", func(ctx context.Context, change objecttree.StorageChange) (shouldContinue bool, err error) {
|
||||
rawCh := make([]byte, len(change.RawChange))
|
||||
copy(rawCh, change.RawChange)
|
||||
change.RawChange = rawCh
|
||||
allChanges = append(allChanges, change)
|
||||
return true, nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
heads, err := settingsStorage.Heads(ctx)
|
||||
require.NoError(t, err)
|
||||
commonSnapshot, err := settingsStorage.CommonSnapshot(ctx)
|
||||
require.NoError(t, err)
|
||||
newStorage, err := spacestorage.New(ctx, spc.Id(), newStore)
|
||||
require.NoError(t, err)
|
||||
newSettingsStorage, err := newStorage.TreeStorage(ctx, settingsId)
|
||||
require.NoError(t, err)
|
||||
err = newSettingsStorage.AddAllNoError(ctx, allChanges, heads, commonSnapshot)
|
||||
require.NoError(t, err)
|
||||
err = spc.Close()
|
||||
require.NoError(t, err)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
storeSetter := fx.storageProvider.(storeSetter)
|
||||
storeSetter.SetStore(sp, newStore)
|
||||
spc, err = fx.spaceService.NewSpace(ctx, sp, Deps{TreeSyncer: mockTreeSyncer{}, SyncStatus: syncstatus.NewNoOpSyncStatus()})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, spc)
|
||||
waitTest := make(chan struct{})
|
||||
fx.treeManager.wait = true
|
||||
fx.treeManager.space = spc
|
||||
fx.treeManager.waitLoad = make(chan struct{})
|
||||
fx.treeManager.deletedIds = nil
|
||||
fx.treeManager.markedIds = nil
|
||||
fx.treeManager.condFunc = func() {
|
||||
if len(fx.treeManager.deletedIds) == len(ids) {
|
||||
close(waitTest)
|
||||
}
|
||||
}
|
||||
err = spc.Init(ctx)
|
||||
require.NoError(t, err)
|
||||
close(fx.treeManager.waitLoad)
|
||||
// waiting until everything is deleted
|
||||
<-waitTest
|
||||
require.Equal(t, len(ids), len(fx.treeManager.deletedIds))
|
||||
}
|
||||
|
|
|
@ -4,10 +4,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -125,12 +122,6 @@ type testTreeContext struct {
|
|||
objTree ObjectTree
|
||||
}
|
||||
|
||||
type testStore struct {
|
||||
anystore.DB
|
||||
path string
|
||||
errAdd bool
|
||||
}
|
||||
|
||||
func createStore(ctx context.Context, t *testing.T) anystore.DB {
|
||||
return createNamedStore(ctx, t, "changes.db")
|
||||
}
|
||||
|
@ -144,9 +135,9 @@ func createNamedStore(ctx context.Context, t *testing.T, name string) anystore.D
|
|||
require.NoError(t, err)
|
||||
unix.Rmdir(path)
|
||||
})
|
||||
return testStore{
|
||||
return TestStore{
|
||||
DB: db,
|
||||
path: path,
|
||||
Path: path,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,68 +150,6 @@ func allChanges(ctx context.Context, t *testing.T, store Storage) (res []*treech
|
|||
return
|
||||
}
|
||||
|
||||
func copyFolder(src string, dst string) error {
|
||||
return filepath.WalkDir(src, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
relPath, err := filepath.Rel(src, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dstPath := filepath.Join(dst, relPath)
|
||||
if d.IsDir() {
|
||||
info, err := d.Info()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.MkdirAll(dstPath, info.Mode())
|
||||
} else {
|
||||
return copyFile(path, dstPath, d)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyFile(src, dst string, d fs.DirEntry) error {
|
||||
srcFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcFile.Close()
|
||||
dstFile, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstFile.Close()
|
||||
_, err = io.Copy(dstFile, srcFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := d.Info()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Chmod(dst, info.Mode())
|
||||
}
|
||||
|
||||
func copyStore(ctx context.Context, t *testing.T, store testStore, name string) anystore.DB {
|
||||
err := store.Checkpoint(ctx, true)
|
||||
require.NoError(t, err)
|
||||
newPath := filepath.Join(t.TempDir(), name)
|
||||
err = copyFolder(store.path, newPath)
|
||||
require.NoError(t, err)
|
||||
db, err := anystore.Open(ctx, newPath, nil)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
err := db.Close()
|
||||
require.NoError(t, err)
|
||||
})
|
||||
return testStore{
|
||||
DB: db,
|
||||
path: newPath,
|
||||
}
|
||||
}
|
||||
|
||||
func prepareAclList(t *testing.T) (list.AclList, *accountdata.AccountKeys) {
|
||||
randKeys, err := accountdata.NewRandom()
|
||||
require.NoError(t, err)
|
||||
|
@ -378,7 +307,7 @@ func TestObjectTree(t *testing.T) {
|
|||
DataType: mockDataType,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
storeB := copyStore(ctx, t, storeA.(testStore), "b")
|
||||
storeB := CopyStore(ctx, t, storeA.(TestStore), "b")
|
||||
bHeadsStorage, err := headstorage.New(ctx, storeB)
|
||||
require.NoError(t, err)
|
||||
bStore, err := NewStorage(ctx, root.Id, bHeadsStorage, storeB)
|
||||
|
@ -506,7 +435,7 @@ func TestObjectTree(t *testing.T) {
|
|||
DataType: mockDataType,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
storeB := copyStore(ctx, t, storeA.(testStore), "b")
|
||||
storeB := CopyStore(ctx, t, storeA.(TestStore), "b")
|
||||
bHeadsStorage, err := headstorage.New(ctx, storeB)
|
||||
require.NoError(t, err)
|
||||
bStore, err := NewStorage(ctx, root.Id, bHeadsStorage, storeB)
|
||||
|
|
|
@ -59,6 +59,7 @@ type Storage interface {
|
|||
Get(ctx context.Context, id string) (StorageChange, error)
|
||||
GetAfterOrder(ctx context.Context, orderId string, iter StorageIterator) error
|
||||
AddAll(ctx context.Context, changes []StorageChange, heads []string, commonSnapshot string) error
|
||||
AddAllNoError(ctx context.Context, changes []StorageChange, heads []string, commonSnapshot string) error
|
||||
Delete(ctx context.Context) error
|
||||
Close() error
|
||||
}
|
||||
|
@ -235,6 +236,36 @@ func (s *storage) AddAll(ctx context.Context, changes []StorageChange, heads []s
|
|||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (s *storage) AddAllNoError(ctx context.Context, changes []StorageChange, heads []string, commonSnapshot string) error {
|
||||
arena := s.arena
|
||||
defer arena.Reset()
|
||||
tx, err := s.store.WriteTx(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create write tx: %w", err)
|
||||
}
|
||||
for _, ch := range changes {
|
||||
ch.TreeId = s.id
|
||||
newVal := newStorageChangeValue(ch, arena)
|
||||
err = s.changesColl.Insert(tx.Context(), newVal)
|
||||
arena.Reset()
|
||||
if err != nil && !errors.Is(err, anystore.ErrDocExists) {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
update := headstorage.HeadsUpdate{
|
||||
Id: s.id,
|
||||
Heads: heads,
|
||||
CommonSnapshot: &commonSnapshot,
|
||||
}
|
||||
err = s.headStorage.UpdateEntryTx(tx.Context(), update)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (s *storage) Delete(ctx context.Context) error {
|
||||
tx, err := s.store.WriteTx(ctx)
|
||||
if err != nil {
|
||||
|
|
|
@ -3,6 +3,10 @@ package objecttree
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
anystore "github.com/anyproto/any-store"
|
||||
|
@ -175,3 +179,71 @@ func (c *MockChangeCreator) CreateNewTreeStorage(t *testing.T, treeId, aclHeadId
|
|||
Storage: storage,
|
||||
}
|
||||
}
|
||||
|
||||
func copyFolder(src string, dst string) error {
|
||||
return filepath.WalkDir(src, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
relPath, err := filepath.Rel(src, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dstPath := filepath.Join(dst, relPath)
|
||||
if d.IsDir() {
|
||||
info, err := d.Info()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.MkdirAll(dstPath, info.Mode())
|
||||
} else {
|
||||
return copyFile(path, dstPath, d)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyFile(src, dst string, d fs.DirEntry) error {
|
||||
srcFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcFile.Close()
|
||||
dstFile, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstFile.Close()
|
||||
_, err = io.Copy(dstFile, srcFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := d.Info()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Chmod(dst, info.Mode())
|
||||
}
|
||||
|
||||
type TestStore struct {
|
||||
anystore.DB
|
||||
Path string
|
||||
errAdd bool
|
||||
}
|
||||
|
||||
func CopyStore(ctx context.Context, t *testing.T, store TestStore, name string) anystore.DB {
|
||||
err := store.Checkpoint(ctx, true)
|
||||
require.NoError(t, err)
|
||||
newPath := filepath.Join(t.TempDir(), name)
|
||||
err = copyFolder(store.Path, newPath)
|
||||
require.NoError(t, err)
|
||||
db, err := anystore.Open(ctx, newPath, nil)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
err := db.Close()
|
||||
require.NoError(t, err)
|
||||
})
|
||||
return TestStore{
|
||||
DB: db,
|
||||
Path: newPath,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -355,6 +355,7 @@ type testTreeManager struct {
|
|||
accService accountService.Service
|
||||
deletedIds []string
|
||||
markedIds []string
|
||||
condFunc func()
|
||||
treesToPut map[string]treestorage.TreeStorageCreatePayload
|
||||
wait bool
|
||||
waitLoad chan struct{}
|
||||
|
@ -376,6 +377,9 @@ func (t *testTreeManager) MarkTreeDeleted(ctx context.Context, spaceId, treeId s
|
|||
t.mx.Lock()
|
||||
defer t.mx.Unlock()
|
||||
t.markedIds = append(t.markedIds, treeId)
|
||||
if t.condFunc != nil {
|
||||
t.condFunc()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -470,6 +474,9 @@ func (t *testTreeManager) DeleteTree(ctx context.Context, spaceId, treeId string
|
|||
}
|
||||
t.deletedIds = append(t.deletedIds, treeId)
|
||||
_, err = t.cache.Remove(ctx, treeId)
|
||||
if t.condFunc != nil {
|
||||
t.condFunc()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,13 @@ import (
|
|||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/anyproto/any-sync/app"
|
||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
||||
"github.com/anyproto/any-sync/commonspace/spacestorage"
|
||||
)
|
||||
|
||||
type spaceStorageProvider struct {
|
||||
rootPath string
|
||||
anyStores map[string]anystore.DB
|
||||
}
|
||||
|
||||
func (s *spaceStorageProvider) Run(ctx context.Context) (err error) {
|
||||
|
@ -33,6 +35,12 @@ func (s *spaceStorageProvider) Name() (name string) {
|
|||
}
|
||||
|
||||
func (s *spaceStorageProvider) WaitSpaceStorage(ctx context.Context, id string) (spacestorage.SpaceStorage, error) {
|
||||
if s.anyStores == nil {
|
||||
s.anyStores = make(map[string]anystore.DB)
|
||||
}
|
||||
if store, ok := s.anyStores[id]; ok {
|
||||
return spacestorage.New(ctx, id, store)
|
||||
}
|
||||
dbPath := path.Join(s.rootPath, id)
|
||||
if _, err := os.Stat(dbPath); err != nil {
|
||||
return nil, err
|
||||
|
@ -41,7 +49,18 @@ func (s *spaceStorageProvider) WaitSpaceStorage(ctx context.Context, id string)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return spacestorage.New(ctx, id, db)
|
||||
testStore := objecttree.TestStore{
|
||||
DB: db,
|
||||
Path: dbPath,
|
||||
}
|
||||
return spacestorage.New(ctx, id, testStore)
|
||||
}
|
||||
|
||||
func (s *spaceStorageProvider) SetStore(id string, store anystore.DB) {
|
||||
if s.anyStores == nil {
|
||||
s.anyStores = make(map[string]anystore.DB)
|
||||
}
|
||||
s.anyStores[id] = store
|
||||
}
|
||||
|
||||
func (s *spaceStorageProvider) SpaceExists(id string) bool {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue