gui, lib/config, lib/model: Support auto-accepting folders (fixes #2299)
Also introduces a new Waiter interface for config changes and segments the configuration GUI. GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4551
This commit is contained in:
committed by
Jakob Borg
parent
c005b8dcb0
commit
445c4edeca
@@ -18,6 +18,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -36,13 +37,14 @@ var device1, device2 protocol.DeviceID
|
||||
var defaultConfig *config.Wrapper
|
||||
var defaultFolderConfig config.FolderConfiguration
|
||||
var defaultFs fs.Filesystem
|
||||
var defaultAutoAcceptCfg config.Configuration
|
||||
|
||||
func init() {
|
||||
device1, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
|
||||
device2, _ = protocol.DeviceIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY")
|
||||
defaultFs = fs.NewFilesystem(fs.FilesystemTypeBasic, "testdata")
|
||||
|
||||
defaultFolderConfig = config.NewFolderConfiguration("default", fs.FilesystemTypeBasic, "testdata")
|
||||
defaultFolderConfig = config.NewFolderConfiguration(protocol.LocalDeviceID, "default", "default", fs.FilesystemTypeBasic, "testdata")
|
||||
defaultFolderConfig.Devices = []config.FolderDeviceConfiguration{{DeviceID: device1}}
|
||||
_defaultConfig := config.Configuration{
|
||||
Folders: []config.FolderConfiguration{defaultFolderConfig},
|
||||
@@ -53,6 +55,17 @@ func init() {
|
||||
},
|
||||
}
|
||||
defaultConfig = config.Wrap("/tmp/test", _defaultConfig)
|
||||
defaultAutoAcceptCfg = config.Configuration{
|
||||
Devices: []config.DeviceConfiguration{
|
||||
{
|
||||
DeviceID: device1,
|
||||
AutoAcceptFolders: true,
|
||||
},
|
||||
},
|
||||
Options: config.OptionsConfiguration{
|
||||
DefaultFolderPath: "testdata",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var testDataExpected = map[string]protocol.FileInfo{
|
||||
@@ -87,6 +100,20 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
func newState(cfg config.Configuration) (*config.Wrapper, *Model) {
|
||||
db := db.OpenMemory()
|
||||
|
||||
wcfg := config.Wrap("/tmp/test", cfg)
|
||||
|
||||
m := NewModel(wcfg, protocol.LocalDeviceID, "syncthing", "dev", db, nil)
|
||||
for _, folder := range cfg.Folders {
|
||||
m.AddFolder(folder)
|
||||
}
|
||||
m.ServeBackground()
|
||||
m.AddConnection(&fakeConnection{id: device1}, protocol.HelloResult{})
|
||||
return wcfg, m
|
||||
}
|
||||
|
||||
func TestRequest(t *testing.T) {
|
||||
db := db.OpenMemory()
|
||||
|
||||
@@ -609,20 +636,6 @@ func TestIntroducer(t *testing.T) {
|
||||
return false
|
||||
}
|
||||
|
||||
newState := func(cfg config.Configuration) (*config.Wrapper, *Model) {
|
||||
db := db.OpenMemory()
|
||||
|
||||
wcfg := config.Wrap("/tmp/test", cfg)
|
||||
|
||||
m := NewModel(wcfg, protocol.LocalDeviceID, "syncthing", "dev", db, nil)
|
||||
for _, folder := range cfg.Folders {
|
||||
m.AddFolder(folder)
|
||||
}
|
||||
m.ServeBackground()
|
||||
m.AddConnection(&fakeConnection{id: device1}, protocol.HelloResult{})
|
||||
return wcfg, m
|
||||
}
|
||||
|
||||
wcfg, m := newState(config.Configuration{
|
||||
Devices: []config.DeviceConfiguration{
|
||||
{
|
||||
@@ -970,6 +983,237 @@ func TestIntroducer(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAutoAcceptRejected(t *testing.T) {
|
||||
// Nothing happens if AutoAcceptFolders not set
|
||||
tcfg := defaultAutoAcceptCfg.Copy()
|
||||
tcfg.Devices[0].AutoAcceptFolders = false
|
||||
wcfg, m := newState(tcfg)
|
||||
id := srand.String(8)
|
||||
defer os.RemoveAll(filepath.Join("testdata", id))
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if _, ok := wcfg.Folder(id); ok || m.folderSharedWith(id, device1) {
|
||||
t.Error("unexpected shared", id)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAutoAcceptNewFolder(t *testing.T) {
|
||||
// New folder
|
||||
wcfg, m := newState(defaultAutoAcceptCfg)
|
||||
id := srand.String(8)
|
||||
defer os.RemoveAll(filepath.Join("testdata", id))
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
if _, ok := wcfg.Folder(id); !ok || !m.folderSharedWith(id, device1) {
|
||||
t.Error("expected shared", id)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAutoAcceptMultipleFolders(t *testing.T) {
|
||||
// Multiple new folders
|
||||
wcfg, m := newState(defaultAutoAcceptCfg)
|
||||
id1 := srand.String(8)
|
||||
defer os.RemoveAll(filepath.Join("testdata", id1))
|
||||
id2 := srand.String(8)
|
||||
defer os.RemoveAll(filepath.Join("testdata", id2))
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id1,
|
||||
Label: id1,
|
||||
},
|
||||
{
|
||||
ID: id2,
|
||||
Label: id2,
|
||||
},
|
||||
},
|
||||
})
|
||||
if _, ok := wcfg.Folder(id1); !ok || !m.folderSharedWith(id1, device1) {
|
||||
t.Error("expected shared", id1)
|
||||
}
|
||||
if _, ok := wcfg.Folder(id2); !ok || !m.folderSharedWith(id2, device1) {
|
||||
t.Error("expected shared", id2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAutoAcceptExistingFolder(t *testing.T) {
|
||||
// Existing folder
|
||||
id := srand.String(8)
|
||||
idOther := srand.String(8) // To check that path does not get changed.
|
||||
defer os.RemoveAll(filepath.Join("testdata", id))
|
||||
|
||||
tcfg := defaultAutoAcceptCfg.Copy()
|
||||
tcfg.Folders = []config.FolderConfiguration{
|
||||
{
|
||||
ID: id,
|
||||
Path: filepath.Join("testdata", idOther), // To check that path does not get changed.
|
||||
},
|
||||
}
|
||||
wcfg, m := newState(tcfg)
|
||||
if _, ok := wcfg.Folder(id); !ok || m.folderSharedWith(id, device1) {
|
||||
t.Error("missing folder, or shared", id)
|
||||
}
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if fcfg, ok := wcfg.Folder(id); !ok || !m.folderSharedWith(id, device1) || fcfg.Path != filepath.Join("testdata", idOther) {
|
||||
t.Error("missing folder, or unshared, or path changed", id)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAutoAcceptNewAndExistingFolder(t *testing.T) {
|
||||
// New and existing folder
|
||||
id1 := srand.String(8)
|
||||
defer os.RemoveAll(filepath.Join("testdata", id1))
|
||||
id2 := srand.String(8)
|
||||
defer os.RemoveAll(filepath.Join("testdata", id2))
|
||||
|
||||
tcfg := defaultAutoAcceptCfg.Copy()
|
||||
tcfg.Folders = []config.FolderConfiguration{
|
||||
{
|
||||
ID: id1,
|
||||
Path: filepath.Join("testdata", id1), // from previous test case, to verify that path doesn't get changed.
|
||||
},
|
||||
}
|
||||
wcfg, m := newState(tcfg)
|
||||
if _, ok := wcfg.Folder(id1); !ok || m.folderSharedWith(id1, device1) {
|
||||
t.Error("missing folder, or shared", id1)
|
||||
}
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id1,
|
||||
Label: id1,
|
||||
},
|
||||
{
|
||||
ID: id2,
|
||||
Label: id2,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
for i, id := range []string{id1, id2} {
|
||||
if _, ok := wcfg.Folder(id); !ok || !m.folderSharedWith(id, device1) {
|
||||
t.Error("missing folder, or unshared", i, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAutoAcceptAlreadyShared(t *testing.T) {
|
||||
// Already shared
|
||||
id := srand.String(8)
|
||||
defer os.RemoveAll(filepath.Join("testdata", id))
|
||||
tcfg := defaultAutoAcceptCfg.Copy()
|
||||
tcfg.Folders = []config.FolderConfiguration{
|
||||
{
|
||||
ID: id,
|
||||
Path: filepath.Join("testdata", id),
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{
|
||||
DeviceID: device1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
wcfg, m := newState(tcfg)
|
||||
if _, ok := wcfg.Folder(id); !ok || !m.folderSharedWith(id, device1) {
|
||||
t.Error("missing folder, or not shared", id)
|
||||
}
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if _, ok := wcfg.Folder(id); !ok || !m.folderSharedWith(id, device1) {
|
||||
t.Error("missing folder, or not shared", id)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAutoAcceptNameConflict(t *testing.T) {
|
||||
id := srand.String(8)
|
||||
label := srand.String(8)
|
||||
os.MkdirAll(filepath.Join("testdata", id), 0777)
|
||||
os.MkdirAll(filepath.Join("testdata", label), 0777)
|
||||
defer os.RemoveAll(filepath.Join("testdata", id))
|
||||
defer os.RemoveAll(filepath.Join("testdata", label))
|
||||
wcfg, m := newState(defaultAutoAcceptCfg)
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: label,
|
||||
},
|
||||
},
|
||||
})
|
||||
if _, ok := wcfg.Folder(id); ok || m.folderSharedWith(id, device1) {
|
||||
t.Error("unexpected folder", id)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAutoAcceptPrefersLabel(t *testing.T) {
|
||||
// Prefers label, falls back to ID.
|
||||
wcfg, m := newState(defaultAutoAcceptCfg)
|
||||
id := srand.String(8)
|
||||
label := srand.String(8)
|
||||
defer os.RemoveAll(filepath.Join("testdata", id))
|
||||
defer os.RemoveAll(filepath.Join("testdata", label))
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: label,
|
||||
},
|
||||
},
|
||||
})
|
||||
if fcfg, ok := wcfg.Folder(id); !ok || !m.folderSharedWith(id, device1) || !strings.HasSuffix(fcfg.Path, label) {
|
||||
t.Error("expected shared, or wrong path", id, label, fcfg.Path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAutoAcceptFallsBackToID(t *testing.T) {
|
||||
// Prefers label, falls back to ID.
|
||||
wcfg, m := newState(defaultAutoAcceptCfg)
|
||||
id := srand.String(8)
|
||||
label := srand.String(8)
|
||||
os.MkdirAll(filepath.Join("testdata", label), 0777)
|
||||
defer os.RemoveAll(filepath.Join("testdata", label))
|
||||
defer os.RemoveAll(filepath.Join("testdata", id))
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: label,
|
||||
},
|
||||
},
|
||||
})
|
||||
if fcfg, ok := wcfg.Folder(id); !ok || !m.folderSharedWith(id, device1) || !strings.HasSuffix(fcfg.Path, id) {
|
||||
t.Error("expected shared, or wrong path", id, label, fcfg.Path)
|
||||
}
|
||||
}
|
||||
|
||||
func changeIgnores(t *testing.T, m *Model, expected []string) {
|
||||
arrEqual := func(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
@@ -1920,7 +2164,9 @@ func TestIssue4357(t *testing.T) {
|
||||
defer m.Stop()
|
||||
|
||||
// Force the model to wire itself and add the folders
|
||||
if err := wrapper.ReplaceBlocking(cfg); err != nil {
|
||||
p, err := wrapper.Replace(cfg)
|
||||
p.Wait()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -1931,7 +2177,9 @@ func TestIssue4357(t *testing.T) {
|
||||
newCfg := wrapper.RawCopy()
|
||||
newCfg.Folders[0].Paused = true
|
||||
|
||||
if err := wrapper.ReplaceBlocking(newCfg); err != nil {
|
||||
p, err = wrapper.Replace(newCfg)
|
||||
p.Wait()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -1943,7 +2191,9 @@ func TestIssue4357(t *testing.T) {
|
||||
t.Error("should still have folder in config")
|
||||
}
|
||||
|
||||
if err := wrapper.ReplaceBlocking(config.Configuration{}); err != nil {
|
||||
p, err = wrapper.Replace(config.Configuration{})
|
||||
p.Wait()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -1952,7 +2202,9 @@ func TestIssue4357(t *testing.T) {
|
||||
}
|
||||
|
||||
// Add the folder back, should be running
|
||||
if err := wrapper.ReplaceBlocking(cfg); err != nil {
|
||||
p, err = wrapper.Replace(cfg)
|
||||
p.Wait()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -1964,7 +2216,9 @@ func TestIssue4357(t *testing.T) {
|
||||
}
|
||||
|
||||
// Should not panic when removing a running folder.
|
||||
if err := wrapper.ReplaceBlocking(config.Configuration{}); err != nil {
|
||||
p, err = wrapper.Replace(config.Configuration{})
|
||||
p.Wait()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -2066,7 +2320,7 @@ func TestIssue2782(t *testing.T) {
|
||||
|
||||
db := db.OpenMemory()
|
||||
m := NewModel(defaultConfig, protocol.LocalDeviceID, "syncthing", "dev", db, nil)
|
||||
m.AddFolder(config.NewFolderConfiguration("default", fs.FilesystemTypeBasic, "~/"+testName+"/synclink/"))
|
||||
m.AddFolder(config.NewFolderConfiguration(protocol.LocalDeviceID, "default", "default", fs.FilesystemTypeBasic, "~/"+testName+"/synclink/"))
|
||||
m.StartFolder("default")
|
||||
m.ServeBackground()
|
||||
defer m.Stop()
|
||||
@@ -2111,7 +2365,7 @@ func TestIndexesForUnknownDevicesDropped(t *testing.T) {
|
||||
func TestSharedWithClearedOnDisconnect(t *testing.T) {
|
||||
dbi := db.OpenMemory()
|
||||
|
||||
fcfg := config.NewFolderConfiguration("default", fs.FilesystemTypeBasic, "testdata")
|
||||
fcfg := config.NewFolderConfiguration(protocol.LocalDeviceID, "default", "default", fs.FilesystemTypeBasic, "testdata")
|
||||
fcfg.Devices = []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
{DeviceID: device2},
|
||||
@@ -2177,7 +2431,7 @@ func TestSharedWithClearedOnDisconnect(t *testing.T) {
|
||||
cfg = cfg.Copy()
|
||||
cfg.Devices = cfg.Devices[:1]
|
||||
|
||||
if err := wcfg.Replace(cfg); err != nil {
|
||||
if _, err := wcfg.Replace(cfg); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -2350,7 +2604,7 @@ func TestNoRequestsFromPausedDevices(t *testing.T) {
|
||||
|
||||
dbi := db.OpenMemory()
|
||||
|
||||
fcfg := config.NewFolderConfiguration("default", fs.FilesystemTypeBasic, "testdata")
|
||||
fcfg := config.NewFolderConfiguration(protocol.LocalDeviceID, "default", "default", fs.FilesystemTypeBasic, "testdata")
|
||||
fcfg.Devices = []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
{DeviceID: device2},
|
||||
|
||||
Reference in New Issue
Block a user