lib: Apply config changes sequentially (ref #5298) (#7188)

This commit is contained in:
Simon Frei
2021-01-15 15:43:34 +01:00
committed by GitHub
parent b2d82da20d
commit f63cdbfcfa
20 changed files with 1032 additions and 790 deletions
+122 -33
View File
@@ -8,9 +8,11 @@ package config
import (
"bytes"
"context"
"encoding/json"
"encoding/xml"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
@@ -21,6 +23,7 @@ import (
"testing"
"github.com/d4l3k/messagediff"
"github.com/thejerf/suture/v4"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/fs"
@@ -95,7 +98,8 @@ func TestDeviceConfig(t *testing.T) {
}
os.RemoveAll(filepath.Join("testdata", DefaultMarkerName))
wr, err := load(cfgFile, device1)
wr, wrCancel, err := copyAndLoad(cfgFile, device1)
defer wrCancel()
if err != nil {
t.Fatal(err)
}
@@ -107,7 +111,7 @@ func TestDeviceConfig(t *testing.T) {
t.Fatal("Unexpected file")
}
cfg := wr.(*wrapper).cfg
cfg := wr.Wrapper.(*wrapper).cfg
expectedFolders := []FolderConfiguration{
{
@@ -170,7 +174,8 @@ func TestDeviceConfig(t *testing.T) {
}
func TestNoListenAddresses(t *testing.T) {
cfg, err := load("testdata/nolistenaddress.xml", device1)
cfg, cfgCancel, err := copyAndLoad("testdata/nolistenaddress.xml", device1)
defer cfgCancel()
if err != nil {
t.Error(err)
}
@@ -228,7 +233,8 @@ func TestOverriddenValues(t *testing.T) {
}
os.Unsetenv("STNOUPGRADE")
cfg, err := load("testdata/overridenvalues.xml", device1)
cfg, cfgCancel, err := copyAndLoad("testdata/overridenvalues.xml", device1)
defer cfgCancel()
if err != nil {
t.Error(err)
}
@@ -269,7 +275,8 @@ func TestDeviceAddressesDynamic(t *testing.T) {
},
}
cfg, err := load("testdata/deviceaddressesdynamic.xml", device4)
cfg, cfgCancel, err := copyAndLoad("testdata/deviceaddressesdynamic.xml", device4)
defer cfgCancel()
if err != nil {
t.Error(err)
}
@@ -314,7 +321,8 @@ func TestDeviceCompression(t *testing.T) {
},
}
cfg, err := load("testdata/devicecompression.xml", device4)
cfg, cfgCancel, err := copyAndLoad("testdata/devicecompression.xml", device4)
defer cfgCancel()
if err != nil {
t.Error(err)
}
@@ -356,7 +364,8 @@ func TestDeviceAddressesStatic(t *testing.T) {
},
}
cfg, err := load("testdata/deviceaddressesstatic.xml", device4)
cfg, cfgCancel, err := copyAndLoad("testdata/deviceaddressesstatic.xml", device4)
defer cfgCancel()
if err != nil {
t.Error(err)
}
@@ -368,7 +377,8 @@ func TestDeviceAddressesStatic(t *testing.T) {
}
func TestVersioningConfig(t *testing.T) {
cfg, err := load("testdata/versioningconfig.xml", device4)
cfg, cfgCancel, err := copyAndLoad("testdata/versioningconfig.xml", device4)
defer cfgCancel()
if err != nil {
t.Error(err)
}
@@ -395,7 +405,8 @@ func TestIssue1262(t *testing.T) {
t.Skipf("path gets converted to absolute as part of the filesystem initialization on linux")
}
cfg, err := load("testdata/issue-1262.xml", device4)
cfg, cfgCancel, err := copyAndLoad("testdata/issue-1262.xml", device4)
defer cfgCancel()
if err != nil {
t.Fatal(err)
}
@@ -409,7 +420,8 @@ func TestIssue1262(t *testing.T) {
}
func TestIssue1750(t *testing.T) {
cfg, err := load("testdata/issue-1750.xml", device4)
cfg, cfgCancel, err := copyAndLoad("testdata/issue-1750.xml", device4)
defer cfgCancel()
if err != nil {
t.Fatal(err)
}
@@ -505,6 +517,7 @@ func TestFolderCheckPath(t *testing.T) {
func TestNewSaveLoad(t *testing.T) {
path := "testdata/temp.xml"
os.Remove(path)
defer os.Remove(path)
exists := func(path string) bool {
_, err := os.Stat(path)
@@ -513,6 +526,7 @@ func TestNewSaveLoad(t *testing.T) {
intCfg := New(device1)
cfg := wrap(path, intCfg, device1)
defer cfg.stop()
if exists(path) {
t.Error(path, "exists")
@@ -527,6 +541,7 @@ func TestNewSaveLoad(t *testing.T) {
}
cfg2, err := load(path, device1)
defer cfg2.stop()
if err != nil {
t.Error(err)
}
@@ -534,8 +549,6 @@ func TestNewSaveLoad(t *testing.T) {
if diff, equal := messagediff.PrettyDiff(cfg.RawCopy(), cfg2.RawCopy()); !equal {
t.Errorf("Configs are not equal. Diff:\n%s", diff)
}
os.Remove(path)
}
func TestPrepare(t *testing.T) {
@@ -553,7 +566,8 @@ func TestPrepare(t *testing.T) {
}
func TestCopy(t *testing.T) {
wrapper, err := load("testdata/example.xml", device1)
wrapper, wrapperCancel, err := copyAndLoad("testdata/example.xml", device1)
defer wrapperCancel()
if err != nil {
t.Fatal(err)
}
@@ -592,7 +606,8 @@ func TestCopy(t *testing.T) {
}
func TestPullOrder(t *testing.T) {
wrapper, err := load("testdata/pullorder.xml", device1)
wrapper, wrapperCleanup, err := copyAndLoad("testdata/pullorder.xml", device1)
defer wrapperCleanup()
if err != nil {
t.Fatal(err)
}
@@ -632,8 +647,9 @@ func TestPullOrder(t *testing.T) {
if err != nil {
t.Fatal(err)
}
wrapper = wrap("testdata/pullorder.xml", cfg, device1)
folders = wrapper.Folders()
wrapper2 := wrap(wrapper.ConfigPath(), cfg, device1)
defer wrapper2.stop()
folders = wrapper2.Folders()
for _, tc := range expected {
if actual := folders[tc.name].Order; actual != tc.order {
@@ -643,7 +659,8 @@ func TestPullOrder(t *testing.T) {
}
func TestLargeRescanInterval(t *testing.T) {
wrapper, err := load("testdata/largeinterval.xml", device1)
wrapper, wrapperCancel, err := copyAndLoad("testdata/largeinterval.xml", device1)
defer wrapperCancel()
if err != nil {
t.Fatal(err)
}
@@ -681,7 +698,8 @@ func TestGUIConfigURL(t *testing.T) {
func TestDuplicateDevices(t *testing.T) {
// Duplicate devices should be removed
wrapper, err := load("testdata/dupdevices.xml", device1)
wrapper, wrapperCancel, err := copyAndLoad("testdata/dupdevices.xml", device1)
defer wrapperCancel()
if err != nil {
t.Fatal(err)
}
@@ -699,7 +717,8 @@ func TestDuplicateDevices(t *testing.T) {
func TestDuplicateFolders(t *testing.T) {
// Duplicate folders are a loading error
_, err := load("testdata/dupfolders.xml", device1)
_, _Cancel, err := copyAndLoad("testdata/dupfolders.xml", device1)
defer _Cancel()
if err == nil || !strings.Contains(err.Error(), errFolderIDDuplicate.Error()) {
t.Fatal(`Expected error to mention "duplicate folder ID":`, err)
}
@@ -710,7 +729,8 @@ func TestEmptyFolderPaths(t *testing.T) {
// get messed up by the prepare steps (e.g., become the current dir or
// get a slash added so that it becomes the root directory or similar).
_, err := load("testdata/nopath.xml", device1)
_, _Cancel, err := copyAndLoad("testdata/nopath.xml", device1)
defer _Cancel()
if err == nil || !strings.Contains(err.Error(), errFolderPathEmpty.Error()) {
t.Fatal("Expected error due to empty folder path, got", err)
}
@@ -779,7 +799,8 @@ func TestIgnoredDevices(t *testing.T) {
// Verify that ignored devices that are also present in the
// configuration are not in fact ignored.
wrapper, err := load("testdata/ignoreddevices.xml", device1)
wrapper, wrapperCancel, err := copyAndLoad("testdata/ignoreddevices.xml", device1)
defer wrapperCancel()
if err != nil {
t.Fatal(err)
}
@@ -797,7 +818,8 @@ func TestIgnoredFolders(t *testing.T) {
// configuration are not in fact ignored.
// Also, verify that folders that are shared with a device are not ignored.
wrapper, err := load("testdata/ignoredfolders.xml", device1)
wrapper, wrapperCancel, err := copyAndLoad("testdata/ignoredfolders.xml", device1)
defer wrapperCancel()
if err != nil {
t.Fatal(err)
}
@@ -833,7 +855,8 @@ func TestIgnoredFolders(t *testing.T) {
func TestGetDevice(t *testing.T) {
// Verify that the Device() call does the right thing
wrapper, err := load("testdata/ignoreddevices.xml", device1)
wrapper, wrapperCancel, err := copyAndLoad("testdata/ignoreddevices.xml", device1)
defer wrapperCancel()
if err != nil {
t.Fatal(err)
}
@@ -860,7 +883,8 @@ func TestGetDevice(t *testing.T) {
}
func TestSharesRemovedOnDeviceRemoval(t *testing.T) {
wrapper, err := load("testdata/example.xml", device1)
wrapper, wrapperCancel, err := copyAndLoad("testdata/example.xml", device1)
defer wrapperCancel()
if err != nil {
t.Errorf("Failed: %s", err)
}
@@ -872,10 +896,7 @@ func TestSharesRemovedOnDeviceRemoval(t *testing.T) {
t.Error("Should have less devices")
}
_, err = wrapper.Replace(raw)
if err != nil {
t.Errorf("Failed: %s", err)
}
replace(t, wrapper, raw)
raw = wrapper.RawCopy()
if len(raw.Folders[0].Devices) > len(raw.Devices) {
@@ -947,6 +968,7 @@ func TestIssue4219(t *testing.T) {
}
w := wrap("/tmp/cfg", cfg, myID)
defer w.stop()
if !w.IgnoredFolder(device2, "t1") {
t.Error("Folder device2 t1 should be ignored")
}
@@ -1157,13 +1179,80 @@ func defaultConfigAsMap() map[string]interface{} {
return tmp
}
func load(path string, myID protocol.DeviceID) (Wrapper, error) {
cfg, _, err := Load(path, myID, events.NoopLogger)
return cfg, err
func copyToTmp(path string) (string, error) {
orig, err := os.Open(path)
if err != nil {
return "", err
}
defer orig.Close()
temp, err := ioutil.TempFile("", "syncthing-configTest-")
if err != nil {
return "", err
}
defer temp.Close()
if _, err := io.Copy(temp, orig); err != nil {
return "", err
}
return temp.Name(), nil
}
func wrap(path string, cfg Configuration, myID protocol.DeviceID) Wrapper {
return Wrap(path, cfg, myID, events.NoopLogger)
func copyAndLoad(path string, myID protocol.DeviceID) (*testWrapper, func(), error) {
temp, err := copyToTmp(path)
if err != nil {
return nil, func() {}, err
}
wrapper, err := load(temp, myID)
if err != nil {
return nil, func() {}, err
}
return wrapper, func() {
wrapper.stop()
os.Remove(temp)
}, nil
}
func load(path string, myID protocol.DeviceID) (*testWrapper, error) {
cfg, _, err := Load(path, myID, events.NoopLogger)
if err != nil {
return nil, err
}
return startWrapper(cfg), nil
}
func wrap(path string, cfg Configuration, myID protocol.DeviceID) *testWrapper {
wrapper := Wrap(path, cfg, myID, events.NoopLogger)
return startWrapper(wrapper)
}
type testWrapper struct {
Wrapper
cancel context.CancelFunc
done chan struct{}
}
func (w *testWrapper) stop() {
w.cancel()
<-w.done
}
func startWrapper(wrapper Wrapper) *testWrapper {
tw := &testWrapper{
Wrapper: wrapper,
done: make(chan struct{}),
}
s, ok := wrapper.(suture.Service)
if !ok {
tw.cancel = func() {}
close(tw.done)
return tw
}
ctx, cancel := context.WithCancel(context.Background())
tw.cancel = cancel
go func() {
s.Serve(ctx)
close(tw.done)
}()
return tw
}
func TestInternalVersioningConfiguration(t *testing.T) {