@@ -25,7 +25,8 @@ func TestRecvOnlyRevertDeletes(t *testing.T) {
|
||||
|
||||
// Get us a model up and running
|
||||
|
||||
m, f := setupROFolder(t)
|
||||
m, f, wcfgCancel := setupROFolder(t)
|
||||
defer wcfgCancel()
|
||||
ffs := f.Filesystem()
|
||||
defer cleanupModel(m)
|
||||
|
||||
@@ -105,7 +106,8 @@ func TestRecvOnlyRevertNeeds(t *testing.T) {
|
||||
|
||||
// Get us a model up and running
|
||||
|
||||
m, f := setupROFolder(t)
|
||||
m, f, wcfgCancel := setupROFolder(t)
|
||||
defer wcfgCancel()
|
||||
ffs := f.Filesystem()
|
||||
defer cleanupModel(m)
|
||||
|
||||
@@ -193,7 +195,8 @@ func TestRecvOnlyRevertNeeds(t *testing.T) {
|
||||
func TestRecvOnlyUndoChanges(t *testing.T) {
|
||||
// Get us a model up and running
|
||||
|
||||
m, f := setupROFolder(t)
|
||||
m, f, wcfgCancel := setupROFolder(t)
|
||||
defer wcfgCancel()
|
||||
ffs := f.Filesystem()
|
||||
defer cleanupModel(m)
|
||||
|
||||
@@ -261,7 +264,8 @@ func TestRecvOnlyUndoChanges(t *testing.T) {
|
||||
func TestRecvOnlyDeletedRemoteDrop(t *testing.T) {
|
||||
// Get us a model up and running
|
||||
|
||||
m, f := setupROFolder(t)
|
||||
m, f, wcfgCancel := setupROFolder(t)
|
||||
defer wcfgCancel()
|
||||
ffs := f.Filesystem()
|
||||
defer cleanupModel(m)
|
||||
|
||||
@@ -324,7 +328,8 @@ func TestRecvOnlyDeletedRemoteDrop(t *testing.T) {
|
||||
func TestRecvOnlyRemoteUndoChanges(t *testing.T) {
|
||||
// Get us a model up and running
|
||||
|
||||
m, f := setupROFolder(t)
|
||||
m, f, wcfgCancel := setupROFolder(t)
|
||||
defer wcfgCancel()
|
||||
ffs := f.Filesystem()
|
||||
defer cleanupModel(m)
|
||||
|
||||
@@ -443,17 +448,17 @@ func setupKnownFiles(t *testing.T, ffs fs.Filesystem, data []byte) []protocol.Fi
|
||||
return knownFiles
|
||||
}
|
||||
|
||||
func setupROFolder(t *testing.T) (*testModel, *receiveOnlyFolder) {
|
||||
func setupROFolder(t *testing.T) (*testModel, *receiveOnlyFolder, context.CancelFunc) {
|
||||
t.Helper()
|
||||
|
||||
w := createTmpWrapper(defaultCfg)
|
||||
w, cancel := createTmpWrapper(defaultCfg)
|
||||
cfg := w.RawCopy()
|
||||
fcfg := testFolderConfigFake()
|
||||
fcfg.ID = "ro"
|
||||
fcfg.Label = "ro"
|
||||
fcfg.Type = config.FolderTypeReceiveOnly
|
||||
cfg.Folders = []config.FolderConfiguration{fcfg}
|
||||
w.Replace(cfg)
|
||||
replace(t, w, cfg)
|
||||
|
||||
m := newModel(t, w, myID, "syncthing", "dev", nil)
|
||||
m.ServeBackground()
|
||||
@@ -464,7 +469,7 @@ func setupROFolder(t *testing.T) (*testModel, *receiveOnlyFolder) {
|
||||
defer m.fmut.RUnlock()
|
||||
f := m.folderRunners["ro"].(*receiveOnlyFolder)
|
||||
|
||||
return m, f
|
||||
return m, f, cancel
|
||||
}
|
||||
|
||||
func writeFile(fs fs.Filesystem, filename string, data []byte, perm fs.FileMode) error {
|
||||
|
||||
@@ -92,8 +92,8 @@ func createFile(t *testing.T, name string, fs fs.Filesystem) protocol.FileInfo {
|
||||
}
|
||||
|
||||
// Sets up a folder and model, but makes sure the services aren't actually running.
|
||||
func setupSendReceiveFolder(t testing.TB, files ...protocol.FileInfo) (*testModel, *sendReceiveFolder) {
|
||||
w, fcfg := tmpDefaultWrapper()
|
||||
func setupSendReceiveFolder(t testing.TB, files ...protocol.FileInfo) (*testModel, *sendReceiveFolder, context.CancelFunc) {
|
||||
w, fcfg, wCancel := tmpDefaultWrapper()
|
||||
// Initialise model and stop immediately.
|
||||
model := setupModel(t, w)
|
||||
model.cancel()
|
||||
@@ -107,10 +107,11 @@ func setupSendReceiveFolder(t testing.TB, files ...protocol.FileInfo) (*testMode
|
||||
f.updateLocalsFromScanning(files)
|
||||
}
|
||||
|
||||
return model, f
|
||||
return model, f, wCancel
|
||||
}
|
||||
|
||||
func cleanupSRFolder(f *sendReceiveFolder, m *testModel) {
|
||||
func cleanupSRFolder(f *sendReceiveFolder, m *testModel, wrapperCancel context.CancelFunc) {
|
||||
wrapperCancel()
|
||||
os.Remove(m.cfg.ConfigPath())
|
||||
os.RemoveAll(f.Filesystem().URI())
|
||||
}
|
||||
@@ -130,8 +131,8 @@ func TestHandleFile(t *testing.T) {
|
||||
requiredFile := existingFile
|
||||
requiredFile.Blocks = blocks[1:]
|
||||
|
||||
m, f := setupSendReceiveFolder(t, existingFile)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t, existingFile)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
|
||||
copyChan := make(chan copyBlocksState, 1)
|
||||
|
||||
@@ -172,8 +173,8 @@ func TestHandleFileWithTemp(t *testing.T) {
|
||||
requiredFile := existingFile
|
||||
requiredFile.Blocks = blocks[1:]
|
||||
|
||||
m, f := setupSendReceiveFolder(t, existingFile)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t, existingFile)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
|
||||
if _, err := prepareTmpFile(f.Filesystem()); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -228,10 +229,10 @@ func TestCopierFinder(t *testing.T) {
|
||||
requiredFile.Blocks = blocks[1:]
|
||||
requiredFile.Name = "file2"
|
||||
|
||||
m, f := setupSendReceiveFolder(t, existingFile)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t, existingFile)
|
||||
f.CopyRangeMethod = method
|
||||
|
||||
defer cleanupSRFolder(f, m)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
|
||||
if _, err := prepareTmpFile(f.Filesystem()); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -309,8 +310,8 @@ func TestCopierFinder(t *testing.T) {
|
||||
|
||||
func TestWeakHash(t *testing.T) {
|
||||
// Setup the model/pull environment
|
||||
model, fo := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(fo, model)
|
||||
model, fo, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(fo, model, wcfgCancel)
|
||||
ffs := fo.Filesystem()
|
||||
|
||||
tempFile := fs.TempName("weakhash")
|
||||
@@ -438,8 +439,8 @@ func TestCopierCleanup(t *testing.T) {
|
||||
// Create a file
|
||||
file := setupFile("test", []int{0})
|
||||
file.Size = 1
|
||||
m, f := setupSendReceiveFolder(t, file)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t, file)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
|
||||
file.Blocks = []protocol.BlockInfo{blocks[1]}
|
||||
file.Version = file.Version.Update(myID.Short())
|
||||
@@ -471,8 +472,8 @@ func TestCopierCleanup(t *testing.T) {
|
||||
func TestDeregisterOnFailInCopy(t *testing.T) {
|
||||
file := setupFile("filex", []int{0, 2, 0, 0, 5, 0, 0, 8})
|
||||
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
|
||||
// Set up our evet subscription early
|
||||
s := m.evLogger.Subscribe(events.ItemFinished)
|
||||
@@ -571,8 +572,8 @@ func TestDeregisterOnFailInCopy(t *testing.T) {
|
||||
func TestDeregisterOnFailInPull(t *testing.T) {
|
||||
file := setupFile("filex", []int{0, 2, 0, 0, 5, 0, 0, 8})
|
||||
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
|
||||
// Set up our evet subscription early
|
||||
s := m.evLogger.Subscribe(events.ItemFinished)
|
||||
@@ -674,8 +675,8 @@ func TestDeregisterOnFailInPull(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIssue3164(t *testing.T) {
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
ffs := f.Filesystem()
|
||||
tmpDir := ffs.URI()
|
||||
|
||||
@@ -765,8 +766,8 @@ func TestDiffEmpty(t *testing.T) {
|
||||
// option is true and the permissions do not match between the file on disk and
|
||||
// in the db.
|
||||
func TestDeleteIgnorePerms(t *testing.T) {
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
ffs := f.Filesystem()
|
||||
f.IgnorePerms = true
|
||||
|
||||
@@ -803,8 +804,8 @@ func TestCopyOwner(t *testing.T) {
|
||||
// Set up a folder with the CopyParentOwner bit and backed by a fake
|
||||
// filesystem.
|
||||
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
f.folder.FolderConfiguration = config.NewFolderConfiguration(m.id, f.ID, f.Label, fs.FilesystemTypeFake, "/TestCopyOwner")
|
||||
f.folder.FolderConfiguration.CopyOwnershipFromParent = true
|
||||
|
||||
@@ -906,8 +907,8 @@ func TestCopyOwner(t *testing.T) {
|
||||
// TestSRConflictReplaceFileByDir checks that a conflict is created when an existing file
|
||||
// is replaced with a directory and versions are conflicting
|
||||
func TestSRConflictReplaceFileByDir(t *testing.T) {
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
ffs := f.Filesystem()
|
||||
|
||||
name := "foo"
|
||||
@@ -938,8 +939,8 @@ func TestSRConflictReplaceFileByDir(t *testing.T) {
|
||||
// TestSRConflictReplaceFileByLink checks that a conflict is created when an existing file
|
||||
// is replaced with a link and versions are conflicting
|
||||
func TestSRConflictReplaceFileByLink(t *testing.T) {
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
ffs := f.Filesystem()
|
||||
|
||||
name := "foo"
|
||||
@@ -971,8 +972,8 @@ func TestSRConflictReplaceFileByLink(t *testing.T) {
|
||||
// TestDeleteBehindSymlink checks that we don't delete or schedule a scan
|
||||
// when trying to delete a file behind a symlink.
|
||||
func TestDeleteBehindSymlink(t *testing.T) {
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
ffs := f.Filesystem()
|
||||
|
||||
destDir := createTmpDir()
|
||||
@@ -1022,8 +1023,8 @@ func TestDeleteBehindSymlink(t *testing.T) {
|
||||
|
||||
// Reproduces https://github.com/syncthing/syncthing/issues/6559
|
||||
func TestPullCtxCancel(t *testing.T) {
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
|
||||
pullChan := make(chan pullBlockState)
|
||||
finisherChan := make(chan *sharedPullerState)
|
||||
@@ -1064,8 +1065,8 @@ func TestPullCtxCancel(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPullDeleteUnscannedDir(t *testing.T) {
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
ffs := f.Filesystem()
|
||||
|
||||
dir := "foobar"
|
||||
@@ -1093,8 +1094,8 @@ func TestPullDeleteUnscannedDir(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPullCaseOnlyPerformFinish(t *testing.T) {
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
ffs := f.Filesystem()
|
||||
|
||||
name := "foo"
|
||||
@@ -1154,8 +1155,8 @@ func TestPullCaseOnlySymlink(t *testing.T) {
|
||||
}
|
||||
|
||||
func testPullCaseOnlyDirOrSymlink(t *testing.T, dir bool) {
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
ffs := f.Filesystem()
|
||||
|
||||
name := "foo"
|
||||
@@ -1209,8 +1210,8 @@ func testPullCaseOnlyDirOrSymlink(t *testing.T, dir bool) {
|
||||
}
|
||||
|
||||
func TestPullTempFileCaseConflict(t *testing.T) {
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
|
||||
copyChan := make(chan copyBlocksState, 1)
|
||||
|
||||
@@ -1235,8 +1236,8 @@ func TestPullTempFileCaseConflict(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPullCaseOnlyRename(t *testing.T) {
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
|
||||
// tempNameConfl := fs.TempName(confl)
|
||||
|
||||
@@ -1278,8 +1279,8 @@ func TestPullSymlinkOverExistingWindows(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
|
||||
name := "foo"
|
||||
if fd, err := f.mtimefs.Create(name); err != nil {
|
||||
@@ -1318,8 +1319,8 @@ func TestPullSymlinkOverExistingWindows(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPullDeleteCaseConflict(t *testing.T) {
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
|
||||
name := "foo"
|
||||
fi := protocol.FileInfo{Name: "Foo"}
|
||||
@@ -1352,8 +1353,8 @@ func TestPullDeleteCaseConflict(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPullDeleteIgnoreChildDir(t *testing.T) {
|
||||
m, f := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m)
|
||||
m, f, wcfgCancel := setupSendReceiveFolder(t)
|
||||
defer cleanupSRFolder(f, m, wcfgCancel)
|
||||
|
||||
parent := "parent"
|
||||
del := "ignored"
|
||||
|
||||
+59
-52
@@ -136,6 +136,7 @@ type model struct {
|
||||
// such as scans and pulls.
|
||||
folderIOLimiter *byteSemaphore
|
||||
fatalChan chan error
|
||||
started chan struct{}
|
||||
|
||||
// fields protected by fmut
|
||||
fmut sync.RWMutex
|
||||
@@ -162,7 +163,6 @@ type model struct {
|
||||
|
||||
// for testing only
|
||||
foldersRunning int32
|
||||
started chan struct{}
|
||||
}
|
||||
|
||||
type folderFactory func(*model, *db.FileSet, *ignore.Matcher, config.FolderConfiguration, versioner.Versioner, events.Logger, *byteSemaphore) service
|
||||
@@ -221,6 +221,7 @@ func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersio
|
||||
globalRequestLimiter: newByteSemaphore(1024 * cfg.Options().MaxConcurrentIncomingRequestKiB()),
|
||||
folderIOLimiter: newByteSemaphore(cfg.Options().MaxFolderConcurrency()),
|
||||
fatalChan: make(chan error),
|
||||
started: make(chan struct{}),
|
||||
|
||||
// fields protected by fmut
|
||||
fmut: sync.NewRWMutex(),
|
||||
@@ -243,9 +244,6 @@ func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersio
|
||||
deviceDownloads: make(map[protocol.DeviceID]*deviceDownloadState),
|
||||
remotePausedFolders: make(map[protocol.DeviceID]map[string]struct{}),
|
||||
indexSenders: make(map[protocol.DeviceID]*indexSenderRegistry),
|
||||
|
||||
// for testing only
|
||||
started: make(chan struct{}),
|
||||
}
|
||||
for devID := range cfg.Devices() {
|
||||
m.deviceStatRefs[devID] = stats.NewDeviceStatisticsReference(m.db, devID)
|
||||
@@ -259,10 +257,10 @@ func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersio
|
||||
func (m *model) serve(ctx context.Context) error {
|
||||
defer m.closeAllConnectionsAndWait()
|
||||
|
||||
m.cfg.Subscribe(m)
|
||||
cfg := m.cfg.Subscribe(m)
|
||||
defer m.cfg.Unsubscribe(m)
|
||||
|
||||
if err := m.initFolders(); err != nil {
|
||||
if err := m.initFolders(cfg); err != nil {
|
||||
close(m.started)
|
||||
return svcutil.AsFatalErr(err, svcutil.ExitError)
|
||||
}
|
||||
@@ -277,17 +275,14 @@ func (m *model) serve(ctx context.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *model) initFolders() error {
|
||||
cacheIgnoredFiles := m.cfg.Options().CacheIgnoredFiles
|
||||
existingDevices := m.cfg.Devices()
|
||||
existingFolders := m.cfg.Folders()
|
||||
clusterConfigDevices := make(deviceIDSet, len(existingDevices))
|
||||
for _, folderCfg := range existingFolders {
|
||||
func (m *model) initFolders(cfg config.Configuration) error {
|
||||
clusterConfigDevices := make(deviceIDSet, len(cfg.Devices))
|
||||
for _, folderCfg := range cfg.Folders {
|
||||
if folderCfg.Paused {
|
||||
folderCfg.CreateRoot()
|
||||
continue
|
||||
}
|
||||
err := m.newFolder(folderCfg, cacheIgnoredFiles)
|
||||
err := m.newFolder(folderCfg, cfg.Options.CacheIgnoredFiles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -295,7 +290,7 @@ func (m *model) initFolders() error {
|
||||
}
|
||||
|
||||
ignoredDevices := observedDeviceSet(m.cfg.IgnoredDevices())
|
||||
m.cleanPending(existingDevices, existingFolders, ignoredDevices, nil)
|
||||
m.cleanPending(cfg.DeviceMap(), cfg.FolderMap(), ignoredDevices, nil)
|
||||
|
||||
m.resendClusterConfig(clusterConfigDevices.AsSlice())
|
||||
return nil
|
||||
@@ -1184,7 +1179,6 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
|
||||
panic("bug: ClusterConfig called on closed or nonexistent connection")
|
||||
}
|
||||
|
||||
changed := false
|
||||
deviceCfg, ok := m.cfg.Device(deviceID)
|
||||
if !ok {
|
||||
l.Debugln("Device disappeared from config while processing cluster-config")
|
||||
@@ -1219,21 +1213,33 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
|
||||
|
||||
// Needs to happen outside of the fmut, as can cause CommitConfiguration
|
||||
if deviceCfg.AutoAcceptFolders {
|
||||
changedFolders := make([]config.FolderConfiguration, 0, len(cm.Folders))
|
||||
for _, folder := range cm.Folders {
|
||||
if fcfg, fchanged := m.handleAutoAccepts(deviceID, folder, ccDeviceInfos[folder.ID]); fchanged {
|
||||
changedFolders = append(changedFolders, fcfg)
|
||||
w, _ := m.cfg.Modify(func(cfg *config.Configuration) {
|
||||
changedFcfg := make(map[string]config.FolderConfiguration)
|
||||
haveFcfg := cfg.FolderMap()
|
||||
for _, folder := range cm.Folders {
|
||||
from, ok := haveFcfg[folder.ID]
|
||||
if to, changed := m.handleAutoAccepts(deviceID, folder, ccDeviceInfos[folder.ID], from, ok, cfg.Options.DefaultFolderPath); changed {
|
||||
changedFcfg[folder.ID] = to
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(changedFolders) > 0 {
|
||||
// Need to wait for the waiter, as this calls CommitConfiguration,
|
||||
// which sets up the folder and as we return from this call,
|
||||
// ClusterConfig starts poking at m.folderFiles and other things
|
||||
// that might not exist until the config is committed.
|
||||
w, _ := m.cfg.SetFolders(changedFolders)
|
||||
w.Wait()
|
||||
changed = true
|
||||
}
|
||||
if len(changedFcfg) == 0 {
|
||||
return
|
||||
}
|
||||
for i := range cfg.Folders {
|
||||
if fcfg, ok := changedFcfg[cfg.Folders[i].ID]; ok {
|
||||
cfg.Folders[i] = fcfg
|
||||
delete(changedFcfg, cfg.Folders[i].ID)
|
||||
}
|
||||
}
|
||||
for _, fcfg := range changedFcfg {
|
||||
cfg.Folders = append(cfg.Folders, fcfg)
|
||||
}
|
||||
})
|
||||
// Need to wait for the waiter, as this calls CommitConfiguration,
|
||||
// which sets up the folder and as we return from this call,
|
||||
// ClusterConfig starts poking at m.folderFiles and other things
|
||||
// that might not exist until the config is committed.
|
||||
w.Wait()
|
||||
}
|
||||
|
||||
tempIndexFolders, paused, err := m.ccHandleFolders(cm.Folders, deviceCfg, ccDeviceInfos, indexSenderRegistry)
|
||||
@@ -1257,11 +1263,12 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
|
||||
}
|
||||
|
||||
if deviceCfg.Introducer {
|
||||
folders, devices, foldersDevices, introduced := m.handleIntroductions(deviceCfg, cm)
|
||||
folders, devices, deintroduced := m.handleDeintroductions(deviceCfg, foldersDevices, folders, devices)
|
||||
if introduced || deintroduced {
|
||||
changed = true
|
||||
cfg := m.cfg.RawCopy()
|
||||
m.cfg.Modify(func(cfg *config.Configuration) {
|
||||
folders, devices, foldersDevices, introduced := m.handleIntroductions(deviceCfg, cm, cfg.FolderMap(), cfg.DeviceMap())
|
||||
folders, devices, deintroduced := m.handleDeintroductions(deviceCfg, foldersDevices, folders, devices)
|
||||
if !introduced && !deintroduced {
|
||||
return
|
||||
}
|
||||
cfg.Folders = make([]config.FolderConfiguration, 0, len(folders))
|
||||
for _, fcfg := range folders {
|
||||
cfg.Folders = append(cfg.Folders, fcfg)
|
||||
@@ -1270,14 +1277,7 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
|
||||
for _, dcfg := range devices {
|
||||
cfg.Devices = append(cfg.Devices, dcfg)
|
||||
}
|
||||
m.cfg.Replace(cfg)
|
||||
}
|
||||
}
|
||||
|
||||
if changed {
|
||||
if err := m.cfg.Save(); err != nil {
|
||||
l.Warnln("Failed to save config", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -1492,10 +1492,8 @@ func (m *model) resendClusterConfig(ids []protocol.DeviceID) {
|
||||
}
|
||||
|
||||
// handleIntroductions handles adding devices/folders that are shared by an introducer device
|
||||
func (m *model) handleIntroductions(introducerCfg config.DeviceConfiguration, cm protocol.ClusterConfig) (map[string]config.FolderConfiguration, map[protocol.DeviceID]config.DeviceConfiguration, folderDeviceSet, bool) {
|
||||
func (m *model) handleIntroductions(introducerCfg config.DeviceConfiguration, cm protocol.ClusterConfig, folders map[string]config.FolderConfiguration, devices map[protocol.DeviceID]config.DeviceConfiguration) (map[string]config.FolderConfiguration, map[protocol.DeviceID]config.DeviceConfiguration, folderDeviceSet, bool) {
|
||||
changed := false
|
||||
folders := m.cfg.Folders()
|
||||
devices := m.cfg.Devices()
|
||||
|
||||
foldersDevices := make(folderDeviceSet)
|
||||
|
||||
@@ -1521,7 +1519,7 @@ func (m *model) handleIntroductions(introducerCfg config.DeviceConfiguration, cm
|
||||
|
||||
foldersDevices.set(device.ID, folder.ID)
|
||||
|
||||
if _, ok := m.cfg.Device(device.ID); !ok {
|
||||
if _, ok := devices[device.ID]; !ok {
|
||||
// The device is currently unknown. Add it to the config.
|
||||
devices[device.ID] = m.introduceDevice(device, introducerCfg)
|
||||
} else if fcfg.SharedWith(device.ID) {
|
||||
@@ -1602,9 +1600,8 @@ func (m *model) handleDeintroductions(introducerCfg config.DeviceConfiguration,
|
||||
|
||||
// handleAutoAccepts handles adding and sharing folders for devices that have
|
||||
// AutoAcceptFolders set to true.
|
||||
func (m *model) handleAutoAccepts(deviceID protocol.DeviceID, folder protocol.Folder, ccDeviceInfos *indexSenderStartInfo) (config.FolderConfiguration, bool) {
|
||||
if cfg, ok := m.cfg.Folder(folder.ID); !ok {
|
||||
defaultPath := m.cfg.Options().DefaultFolderPath
|
||||
func (m *model) handleAutoAccepts(deviceID protocol.DeviceID, folder protocol.Folder, ccDeviceInfos *indexSenderStartInfo, cfg config.FolderConfiguration, haveCfg bool, defaultPath string) (config.FolderConfiguration, bool) {
|
||||
if !haveCfg {
|
||||
defaultPathFs := fs.NewFilesystem(fs.FilesystemTypeBasic, defaultPath)
|
||||
pathAlternatives := []string{
|
||||
fs.SanitizePath(folder.Label),
|
||||
@@ -2179,9 +2176,16 @@ func (m *model) AddConnection(conn protocol.Connection, hello protocol.Hello) {
|
||||
conn.ClusterConfig(cm)
|
||||
|
||||
if (device.Name == "" || m.cfg.Options().OverwriteRemoteDevNames) && hello.DeviceName != "" {
|
||||
device.Name = hello.DeviceName
|
||||
m.cfg.SetDevice(device)
|
||||
m.cfg.Save()
|
||||
m.cfg.Modify(func(cfg *config.Configuration) {
|
||||
for i := range cfg.Devices {
|
||||
if cfg.Devices[i].DeviceID == deviceID {
|
||||
if cfg.Devices[i].Name == "" || cfg.Options.OverwriteRemoteDevNames {
|
||||
cfg.Devices[i].Name = hello.DeviceName
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
m.deviceWasSeen(deviceID)
|
||||
@@ -2651,6 +2655,9 @@ func (m *model) VerifyConfiguration(from, to config.Configuration) error {
|
||||
func (m *model) CommitConfiguration(from, to config.Configuration) bool {
|
||||
// TODO: This should not use reflect, and should take more care to try to handle stuff without restart.
|
||||
|
||||
// Delay processing config changes until after the initial setup
|
||||
<-m.started
|
||||
|
||||
// Go through the folder configs and figure out if we need to restart or not.
|
||||
|
||||
// Tracks devices affected by any configuration change to resend ClusterConfig.
|
||||
|
||||
+196
-231
File diff suppressed because it is too large
Load Diff
@@ -60,11 +60,16 @@ func TestProgressEmitter(t *testing.T) {
|
||||
|
||||
w := evLogger.Subscribe(events.DownloadProgress)
|
||||
|
||||
c := createTmpWrapper(config.Configuration{})
|
||||
c, cfgCancel := createTmpWrapper(config.Configuration{})
|
||||
defer os.Remove(c.ConfigPath())
|
||||
c.SetOptions(config.OptionsConfiguration{
|
||||
ProgressUpdateIntervalS: 60, // irrelevant, but must be positive
|
||||
defer cfgCancel()
|
||||
waiter, err := c.Modify(func(cfg *config.Configuration) {
|
||||
cfg.Options.ProgressUpdateIntervalS = 60 // irrelevant, but must be positive
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
waiter.Wait()
|
||||
|
||||
p := NewProgressEmitter(c, evLogger)
|
||||
go p.Serve(ctx)
|
||||
@@ -109,12 +114,17 @@ func TestProgressEmitter(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSendDownloadProgressMessages(t *testing.T) {
|
||||
c := createTmpWrapper(config.Configuration{})
|
||||
c, cfgCancel := createTmpWrapper(config.Configuration{})
|
||||
defer os.Remove(c.ConfigPath())
|
||||
c.SetOptions(config.OptionsConfiguration{
|
||||
ProgressUpdateIntervalS: 60, // irrelevant, but must be positive
|
||||
TempIndexMinBlocks: 10,
|
||||
defer cfgCancel()
|
||||
waiter, err := c.Modify(func(cfg *config.Configuration) {
|
||||
cfg.Options.ProgressUpdateIntervalS = 60 // irrelevant, but must be positive
|
||||
cfg.Options.TempIndexMinBlocks = 10
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
waiter.Wait()
|
||||
|
||||
fc := &fakeConnection{}
|
||||
|
||||
|
||||
+45
-37
@@ -29,7 +29,8 @@ func TestRequestSimple(t *testing.T) {
|
||||
// Verify that the model performs a request and creates a file based on
|
||||
// an incoming index update.
|
||||
|
||||
m, fc, fcfg := setupModelWithConnection(t)
|
||||
m, fc, fcfg, wcfgCancel := setupModelWithConnection(t)
|
||||
defer wcfgCancel()
|
||||
tfs := fcfg.Filesystem()
|
||||
defer cleanupModelAndRemoveDir(m, tfs.URI())
|
||||
|
||||
@@ -72,7 +73,8 @@ func TestSymlinkTraversalRead(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
m, fc, fcfg := setupModelWithConnection(t)
|
||||
m, fc, fcfg, wcfgCancel := setupModelWithConnection(t)
|
||||
defer wcfgCancel()
|
||||
defer cleanupModelAndRemoveDir(m, fcfg.Filesystem().URI())
|
||||
|
||||
// We listen for incoming index updates and trigger when we see one for
|
||||
@@ -115,7 +117,8 @@ func TestSymlinkTraversalWrite(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
m, fc, fcfg := setupModelWithConnection(t)
|
||||
m, fc, fcfg, wcfgCancel := setupModelWithConnection(t)
|
||||
defer wcfgCancel()
|
||||
defer cleanupModelAndRemoveDir(m, fcfg.Filesystem().URI())
|
||||
|
||||
// We listen for incoming index updates and trigger when we see one for
|
||||
@@ -174,7 +177,8 @@ func TestSymlinkTraversalWrite(t *testing.T) {
|
||||
func TestRequestCreateTmpSymlink(t *testing.T) {
|
||||
// Test that an update for a temporary file is invalidated
|
||||
|
||||
m, fc, fcfg := setupModelWithConnection(t)
|
||||
m, fc, fcfg, wcfgCancel := setupModelWithConnection(t)
|
||||
defer wcfgCancel()
|
||||
defer cleanupModelAndRemoveDir(m, fcfg.Filesystem().URI())
|
||||
|
||||
// We listen for incoming index updates and trigger when we see one for
|
||||
@@ -216,14 +220,15 @@ func TestRequestVersioningSymlinkAttack(t *testing.T) {
|
||||
// Sets up a folder with trashcan versioning and tries to use a
|
||||
// deleted symlink to escape
|
||||
|
||||
w, fcfg := tmpDefaultWrapper()
|
||||
w, fcfg, wCancel := tmpDefaultWrapper()
|
||||
defer wCancel()
|
||||
defer func() {
|
||||
os.RemoveAll(fcfg.Filesystem().URI())
|
||||
os.Remove(w.ConfigPath())
|
||||
}()
|
||||
|
||||
fcfg.Versioning = config.VersioningConfiguration{Type: "trashcan"}
|
||||
w.SetFolder(fcfg)
|
||||
setFolder(t, w, fcfg)
|
||||
m, fc := setupModelWithConnectionFromWrapper(t, w)
|
||||
defer cleanupModel(m)
|
||||
|
||||
@@ -293,11 +298,12 @@ func TestPullInvalidIgnoredSR(t *testing.T) {
|
||||
|
||||
// This test checks that (un-)ignored/invalid/deleted files are treated as expected.
|
||||
func pullInvalidIgnored(t *testing.T, ft config.FolderType) {
|
||||
w := createTmpWrapper(defaultCfgWrapper.RawCopy())
|
||||
w, wCancel := createTmpWrapper(defaultCfgWrapper.RawCopy())
|
||||
defer wCancel()
|
||||
fcfg := testFolderConfigTmp()
|
||||
fss := fcfg.Filesystem()
|
||||
fcfg.Type = ft
|
||||
w.SetFolder(fcfg)
|
||||
setFolder(t, w, fcfg)
|
||||
m := setupModel(t, w)
|
||||
defer cleanupModelAndRemoveDir(m, fss.URI())
|
||||
|
||||
@@ -420,7 +426,8 @@ func pullInvalidIgnored(t *testing.T, ft config.FolderType) {
|
||||
}
|
||||
|
||||
func TestIssue4841(t *testing.T) {
|
||||
m, fc, fcfg := setupModelWithConnection(t)
|
||||
m, fc, fcfg, wcfgCancel := setupModelWithConnection(t)
|
||||
defer wcfgCancel()
|
||||
defer cleanupModelAndRemoveDir(m, fcfg.Filesystem().URI())
|
||||
|
||||
received := make(chan []protocol.FileInfo)
|
||||
@@ -464,7 +471,8 @@ func TestIssue4841(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRescanIfHaveInvalidContent(t *testing.T) {
|
||||
m, fc, fcfg := setupModelWithConnection(t)
|
||||
m, fc, fcfg, wcfgCancel := setupModelWithConnection(t)
|
||||
defer wcfgCancel()
|
||||
tfs := fcfg.Filesystem()
|
||||
defer cleanupModelAndRemoveDir(m, tfs.URI())
|
||||
|
||||
@@ -530,7 +538,8 @@ func TestRescanIfHaveInvalidContent(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestParentDeletion(t *testing.T) {
|
||||
m, fc, fcfg := setupModelWithConnection(t)
|
||||
m, fc, fcfg, wcfgCancel := setupModelWithConnection(t)
|
||||
defer wcfgCancel()
|
||||
testFs := fcfg.Filesystem()
|
||||
defer cleanupModelAndRemoveDir(m, testFs.URI())
|
||||
|
||||
@@ -609,7 +618,8 @@ func TestRequestSymlinkWindows(t *testing.T) {
|
||||
t.Skip("windows specific test")
|
||||
}
|
||||
|
||||
m, fc, fcfg := setupModelWithConnection(t)
|
||||
m, fc, fcfg, wcfgCancel := setupModelWithConnection(t)
|
||||
defer wcfgCancel()
|
||||
defer cleanupModelAndRemoveDir(m, fcfg.Filesystem().URI())
|
||||
|
||||
received := make(chan []protocol.FileInfo)
|
||||
@@ -677,7 +687,8 @@ func equalContents(path string, contents []byte) error {
|
||||
}
|
||||
|
||||
func TestRequestRemoteRenameChanged(t *testing.T) {
|
||||
m, fc, fcfg := setupModelWithConnection(t)
|
||||
m, fc, fcfg, wcfgCancel := setupModelWithConnection(t)
|
||||
defer wcfgCancel()
|
||||
tfs := fcfg.Filesystem()
|
||||
tmpDir := tfs.URI()
|
||||
defer cleanupModelAndRemoveDir(m, tfs.URI())
|
||||
@@ -812,7 +823,8 @@ func TestRequestRemoteRenameChanged(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRequestRemoteRenameConflict(t *testing.T) {
|
||||
m, fc, fcfg := setupModelWithConnection(t)
|
||||
m, fc, fcfg, wcfgCancel := setupModelWithConnection(t)
|
||||
defer wcfgCancel()
|
||||
tfs := fcfg.Filesystem()
|
||||
tmpDir := tfs.URI()
|
||||
defer cleanupModelAndRemoveDir(m, tmpDir)
|
||||
@@ -903,7 +915,8 @@ func TestRequestRemoteRenameConflict(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRequestDeleteChanged(t *testing.T) {
|
||||
m, fc, fcfg := setupModelWithConnection(t)
|
||||
m, fc, fcfg, wcfgCancel := setupModelWithConnection(t)
|
||||
defer wcfgCancel()
|
||||
tfs := fcfg.Filesystem()
|
||||
defer cleanupModelAndRemoveDir(m, tfs.URI())
|
||||
|
||||
@@ -972,7 +985,8 @@ func TestRequestDeleteChanged(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNeedFolderFiles(t *testing.T) {
|
||||
m, fc, fcfg := setupModelWithConnection(t)
|
||||
m, fc, fcfg, wcfgCancel := setupModelWithConnection(t)
|
||||
defer wcfgCancel()
|
||||
tfs := fcfg.Filesystem()
|
||||
tmpDir := tfs.URI()
|
||||
defer cleanupModelAndRemoveDir(m, tmpDir)
|
||||
@@ -1020,7 +1034,8 @@ func TestNeedFolderFiles(t *testing.T) {
|
||||
// propagated upon un-ignoring.
|
||||
// https://github.com/syncthing/syncthing/issues/6038
|
||||
func TestIgnoreDeleteUnignore(t *testing.T) {
|
||||
w, fcfg := tmpDefaultWrapper()
|
||||
w, fcfg, wCancel := tmpDefaultWrapper()
|
||||
defer wCancel()
|
||||
m := setupModel(t, w)
|
||||
fss := fcfg.Filesystem()
|
||||
tmpDir := fss.URI()
|
||||
@@ -1120,7 +1135,8 @@ func TestIgnoreDeleteUnignore(t *testing.T) {
|
||||
// TestRequestLastFileProgress checks that the last pulled file (here only) is registered
|
||||
// as in progress.
|
||||
func TestRequestLastFileProgress(t *testing.T) {
|
||||
m, fc, fcfg := setupModelWithConnection(t)
|
||||
m, fc, fcfg, wcfgCancel := setupModelWithConnection(t)
|
||||
defer wcfgCancel()
|
||||
tfs := fcfg.Filesystem()
|
||||
defer cleanupModelAndRemoveDir(m, tfs.URI())
|
||||
|
||||
@@ -1156,7 +1172,8 @@ func TestRequestIndexSenderPause(t *testing.T) {
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
|
||||
m, fc, fcfg := setupModelWithConnection(t)
|
||||
m, fc, fcfg, wcfgCancel := setupModelWithConnection(t)
|
||||
defer wcfgCancel()
|
||||
tfs := fcfg.Filesystem()
|
||||
defer cleanupModelAndRemoveDir(m, tfs.URI())
|
||||
|
||||
@@ -1215,13 +1232,8 @@ func TestRequestIndexSenderPause(t *testing.T) {
|
||||
|
||||
// Local paused and resume
|
||||
|
||||
fcfg.Paused = true
|
||||
waiter, _ := m.cfg.SetFolder(fcfg)
|
||||
waiter.Wait()
|
||||
|
||||
fcfg.Paused = false
|
||||
waiter, _ = m.cfg.SetFolder(fcfg)
|
||||
waiter.Wait()
|
||||
pauseFolder(t, m.cfg, fcfg.ID, true)
|
||||
pauseFolder(t, m.cfg, fcfg.ID, false)
|
||||
|
||||
seq++
|
||||
files[0].Sequence = seq
|
||||
@@ -1238,16 +1250,12 @@ func TestRequestIndexSenderPause(t *testing.T) {
|
||||
cc.Folders[0].Paused = true
|
||||
m.ClusterConfig(device1, cc)
|
||||
|
||||
fcfg.Paused = true
|
||||
waiter, _ = m.cfg.SetFolder(fcfg)
|
||||
waiter.Wait()
|
||||
pauseFolder(t, m.cfg, fcfg.ID, true)
|
||||
|
||||
cc.Folders[0].Paused = false
|
||||
m.ClusterConfig(device1, cc)
|
||||
|
||||
fcfg.Paused = false
|
||||
waiter, _ = m.cfg.SetFolder(fcfg)
|
||||
waiter.Wait()
|
||||
pauseFolder(t, m.cfg, fcfg.ID, false)
|
||||
|
||||
seq++
|
||||
files[0].Sequence = seq
|
||||
@@ -1277,7 +1285,8 @@ func TestRequestIndexSenderPause(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRequestIndexSenderClusterConfigBeforeStart(t *testing.T) {
|
||||
w, fcfg := tmpDefaultWrapper()
|
||||
w, fcfg, wCancel := tmpDefaultWrapper()
|
||||
defer wCancel()
|
||||
tfs := fcfg.Filesystem()
|
||||
dir1 := "foo"
|
||||
dir2 := "bar"
|
||||
@@ -1340,12 +1349,11 @@ func TestRequestIndexSenderClusterConfigBeforeStart(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRequestReceiveEncryptedLocalNoSend(t *testing.T) {
|
||||
w, fcfg := tmpDefaultWrapper()
|
||||
w, fcfg, wCancel := tmpDefaultWrapper()
|
||||
defer wCancel()
|
||||
tfs := fcfg.Filesystem()
|
||||
fcfg.Type = config.FolderTypeReceiveEncrypted
|
||||
waiter, err := w.SetFolder(fcfg)
|
||||
must(t, err)
|
||||
waiter.Wait()
|
||||
setFolder(t, w, fcfg)
|
||||
|
||||
encToken := protocol.PasswordToken(fcfg.ID, "pw")
|
||||
must(t, tfs.Mkdir(config.DefaultMarkerName, 0777))
|
||||
|
||||
+107
-19
@@ -13,6 +13,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/thejerf/suture/v4"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/db"
|
||||
"github.com/syncthing/syncthing/lib/db/backend"
|
||||
@@ -24,12 +26,13 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
myID, device1, device2 protocol.DeviceID
|
||||
defaultCfgWrapper config.Wrapper
|
||||
defaultFolderConfig config.FolderConfiguration
|
||||
defaultFs fs.Filesystem
|
||||
defaultCfg config.Configuration
|
||||
defaultAutoAcceptCfg config.Configuration
|
||||
myID, device1, device2 protocol.DeviceID
|
||||
defaultCfgWrapper config.Wrapper
|
||||
defaultCfgWrapperCancel context.CancelFunc
|
||||
defaultFolderConfig config.FolderConfiguration
|
||||
defaultFs fs.Filesystem
|
||||
defaultCfg config.Configuration
|
||||
defaultAutoAcceptCfg config.Configuration
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -40,12 +43,13 @@ func init() {
|
||||
defaultFolderConfig = testFolderConfig("testdata")
|
||||
defaultFs = defaultFolderConfig.Filesystem()
|
||||
|
||||
defaultCfgWrapper = createTmpWrapper(config.New(myID))
|
||||
_, _ = defaultCfgWrapper.SetDevice(config.NewDeviceConfiguration(device1, "device1"))
|
||||
_, _ = defaultCfgWrapper.SetFolder(defaultFolderConfig)
|
||||
opts := defaultCfgWrapper.Options()
|
||||
opts.KeepTemporariesH = 1
|
||||
_, _ = defaultCfgWrapper.SetOptions(opts)
|
||||
defaultCfgWrapper, defaultCfgWrapperCancel = createTmpWrapper(config.New(myID))
|
||||
waiter, _ := defaultCfgWrapper.Modify(func(cfg *config.Configuration) {
|
||||
cfg.SetDevice(config.NewDeviceConfiguration(device1, "device1"))
|
||||
cfg.SetFolder(defaultFolderConfig)
|
||||
cfg.Options.KeepTemporariesH = 1
|
||||
})
|
||||
waiter.Wait()
|
||||
|
||||
defaultCfg = defaultCfgWrapper.RawCopy()
|
||||
|
||||
@@ -70,11 +74,28 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
func tmpDefaultWrapper() (config.Wrapper, config.FolderConfiguration) {
|
||||
w := createTmpWrapper(defaultCfgWrapper.RawCopy())
|
||||
func createTmpWrapper(cfg config.Configuration) (config.Wrapper, context.CancelFunc) {
|
||||
tmpFile, err := ioutil.TempFile("", "syncthing-testConfig-")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
wrapper := config.Wrap(tmpFile.Name(), cfg, myID, events.NoopLogger)
|
||||
tmpFile.Close()
|
||||
if cfgService, ok := wrapper.(suture.Service); ok {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go cfgService.Serve(ctx)
|
||||
return wrapper, cancel
|
||||
}
|
||||
return wrapper, func() {}
|
||||
}
|
||||
|
||||
func tmpDefaultWrapper() (config.Wrapper, config.FolderConfiguration, context.CancelFunc) {
|
||||
w, cancel := createTmpWrapper(defaultCfgWrapper.RawCopy())
|
||||
fcfg := testFolderConfigTmp()
|
||||
_, _ = w.SetFolder(fcfg)
|
||||
return w, fcfg
|
||||
_, _ = w.Modify(func(cfg *config.Configuration) {
|
||||
cfg.SetFolder(fcfg)
|
||||
})
|
||||
return w, fcfg, cancel
|
||||
}
|
||||
|
||||
func testFolderConfigTmp() config.FolderConfiguration {
|
||||
@@ -96,11 +117,11 @@ func testFolderConfigFake() config.FolderConfiguration {
|
||||
return cfg
|
||||
}
|
||||
|
||||
func setupModelWithConnection(t testing.TB) (*testModel, *fakeConnection, config.FolderConfiguration) {
|
||||
func setupModelWithConnection(t testing.TB) (*testModel, *fakeConnection, config.FolderConfiguration, context.CancelFunc) {
|
||||
t.Helper()
|
||||
w, fcfg := tmpDefaultWrapper()
|
||||
w, fcfg, cancel := tmpDefaultWrapper()
|
||||
m, fc := setupModelWithConnectionFromWrapper(t, w)
|
||||
return m, fc, fcfg
|
||||
return m, fc, fcfg, cancel
|
||||
}
|
||||
|
||||
func setupModelWithConnectionFromWrapper(t testing.TB, w config.Wrapper) (*testModel, *fakeConnection) {
|
||||
@@ -313,3 +334,70 @@ func newFileSet(t testing.TB, folder string, fs fs.Filesystem, ldb *db.Lowlevel)
|
||||
}
|
||||
return fset
|
||||
}
|
||||
|
||||
func replace(t testing.TB, w config.Wrapper, to config.Configuration) {
|
||||
t.Helper()
|
||||
waiter, err := w.Modify(func(cfg *config.Configuration) {
|
||||
*cfg = to
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
waiter.Wait()
|
||||
}
|
||||
|
||||
func pauseFolder(t testing.TB, w config.Wrapper, id string, paused bool) {
|
||||
t.Helper()
|
||||
waiter, err := w.Modify(func(cfg *config.Configuration) {
|
||||
_, i, _ := cfg.Folder(id)
|
||||
cfg.Folders[i].Paused = paused
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
waiter.Wait()
|
||||
}
|
||||
|
||||
func setFolder(t testing.TB, w config.Wrapper, fcfg config.FolderConfiguration) {
|
||||
t.Helper()
|
||||
waiter, err := w.Modify(func(cfg *config.Configuration) {
|
||||
cfg.SetFolder(fcfg)
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
waiter.Wait()
|
||||
}
|
||||
|
||||
func pauseDevice(t testing.TB, w config.Wrapper, id protocol.DeviceID, paused bool) {
|
||||
t.Helper()
|
||||
waiter, err := w.Modify(func(cfg *config.Configuration) {
|
||||
_, i, _ := cfg.Device(id)
|
||||
cfg.Devices[i].Paused = paused
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
waiter.Wait()
|
||||
}
|
||||
|
||||
func setDevice(t testing.TB, w config.Wrapper, device config.DeviceConfiguration) {
|
||||
t.Helper()
|
||||
waiter, err := w.Modify(func(cfg *config.Configuration) {
|
||||
cfg.SetDevice(device)
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
waiter.Wait()
|
||||
}
|
||||
|
||||
func addDevice2(t testing.TB, w config.Wrapper, fcfg config.FolderConfiguration) {
|
||||
waiter, err := w.Modify(func(cfg *config.Configuration) {
|
||||
cfg.SetDevice(config.NewDeviceConfiguration(device2, "device2"))
|
||||
fcfg.Devices = append(fcfg.Devices, config.FolderDeviceConfiguration{DeviceID: device2})
|
||||
cfg.SetFolder(fcfg)
|
||||
})
|
||||
must(t, err)
|
||||
waiter.Wait()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user