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