1
0
Fork 0
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:
mcrakhman 2025-02-05 13:09:32 +01:00
parent daefdae641
commit 4de44b020a
No known key found for this signature in database
GPG key ID: DED12CFEF5B8396B
6 changed files with 357 additions and 343 deletions

View file

@ -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))
}

View file

@ -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)

View file

@ -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 {

View file

@ -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,
}
}

View file

@ -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
}

View file

@ -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 {