lib/model: Introducer can remove stuff it introduced (fixes #1015)
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3522
This commit is contained in:
committed by
Jakob Borg
parent
bfb48b5dde
commit
a1a91d5ef4
@@ -478,6 +478,376 @@ func TestClusterConfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntroducer(t *testing.T) {
|
||||
var introducedByAnyone protocol.DeviceID
|
||||
|
||||
// LocalDeviceID is a magic value meaning don't check introducer
|
||||
contains := func(cfg config.FolderConfiguration, id, introducedBy protocol.DeviceID) bool {
|
||||
for _, dev := range cfg.Devices {
|
||||
if dev.DeviceID.Equals(id) {
|
||||
if introducedBy.Equals(introducedByAnyone) {
|
||||
return true
|
||||
}
|
||||
return introducedBy.Equals(introducedBy)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
newState := func(cfg config.Configuration) (*config.Wrapper, *Model) {
|
||||
db := db.OpenMemory()
|
||||
|
||||
wcfg := config.Wrap("/tmp/test", cfg)
|
||||
|
||||
m := NewModel(wcfg, protocol.LocalDeviceID, "device", "syncthing", "dev", db, nil)
|
||||
for _, folder := range cfg.Folders {
|
||||
m.AddFolder(folder)
|
||||
}
|
||||
m.ServeBackground()
|
||||
m.AddConnection(connections.Connection{
|
||||
IntermediateConnection: connections.IntermediateConnection{
|
||||
Conn: tls.Client(&fakeConn{}, nil),
|
||||
},
|
||||
Connection: &FakeConnection{
|
||||
id: device1,
|
||||
},
|
||||
}, protocol.HelloResult{})
|
||||
return wcfg, m
|
||||
}
|
||||
|
||||
wcfg, m := newState(config.Configuration{
|
||||
Devices: []config.DeviceConfiguration{
|
||||
{
|
||||
DeviceID: device1,
|
||||
Introducer: true,
|
||||
},
|
||||
},
|
||||
Folders: []config.FolderConfiguration{
|
||||
{
|
||||
ID: "folder1",
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "folder2",
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: "folder1",
|
||||
Devices: []protocol.Device{
|
||||
{
|
||||
ID: device2,
|
||||
Introducer: true,
|
||||
SkipIntroductionRemovals: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if newDev, ok := wcfg.Device(device2); !ok || !newDev.Introducer || !newDev.SkipIntroductionRemovals {
|
||||
t.Error("devie 2 missing or wrong flags")
|
||||
}
|
||||
|
||||
if !contains(wcfg.Folders()["folder1"], device2, device1) {
|
||||
t.Error("expected folder 1 to have device2 introduced by device 1")
|
||||
}
|
||||
|
||||
wcfg, m = newState(config.Configuration{
|
||||
Devices: []config.DeviceConfiguration{
|
||||
{
|
||||
DeviceID: device1,
|
||||
Introducer: true,
|
||||
},
|
||||
{
|
||||
DeviceID: device2,
|
||||
IntroducedBy: device1,
|
||||
},
|
||||
},
|
||||
Folders: []config.FolderConfiguration{
|
||||
{
|
||||
ID: "folder1",
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
{DeviceID: device2, IntroducedBy: device1},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "folder2",
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: "folder2",
|
||||
Devices: []protocol.Device{
|
||||
{
|
||||
ID: device2,
|
||||
Introducer: true,
|
||||
SkipIntroductionRemovals: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Should not get introducer, as it's already unset, and it's an existing device.
|
||||
if newDev, ok := wcfg.Device(device2); !ok || newDev.Introducer || newDev.SkipIntroductionRemovals {
|
||||
t.Error("device 2 missing or changed flags")
|
||||
}
|
||||
|
||||
if contains(wcfg.Folders()["folder1"], device2, introducedByAnyone) {
|
||||
t.Error("expected device 2 to be removed from folder 1")
|
||||
}
|
||||
|
||||
if !contains(wcfg.Folders()["folder2"], device2, device1) {
|
||||
t.Error("expected device 2 to be added to folder 2")
|
||||
}
|
||||
|
||||
wcfg, m = newState(config.Configuration{
|
||||
Devices: []config.DeviceConfiguration{
|
||||
{
|
||||
DeviceID: device1,
|
||||
Introducer: true,
|
||||
},
|
||||
{
|
||||
DeviceID: device2,
|
||||
IntroducedBy: device1,
|
||||
},
|
||||
},
|
||||
Folders: []config.FolderConfiguration{
|
||||
{
|
||||
ID: "folder1",
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
{DeviceID: device2, IntroducedBy: device1},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "folder2",
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
{DeviceID: device2, IntroducedBy: device1},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{})
|
||||
|
||||
if _, ok := wcfg.Device(device2); ok {
|
||||
t.Error("device 2 should have been removed")
|
||||
}
|
||||
|
||||
if contains(wcfg.Folders()["folder1"], device2, introducedByAnyone) {
|
||||
t.Error("expected device 2 to be removed from folder 1")
|
||||
}
|
||||
|
||||
if contains(wcfg.Folders()["folder2"], device2, introducedByAnyone) {
|
||||
t.Error("expected device 2 to be removed from folder 2")
|
||||
}
|
||||
|
||||
// Two cases when removals should not happen
|
||||
// 1. Introducer flag no longer set on device
|
||||
|
||||
wcfg, m = newState(config.Configuration{
|
||||
Devices: []config.DeviceConfiguration{
|
||||
{
|
||||
DeviceID: device1,
|
||||
Introducer: false,
|
||||
},
|
||||
{
|
||||
DeviceID: device2,
|
||||
IntroducedBy: device1,
|
||||
},
|
||||
},
|
||||
Folders: []config.FolderConfiguration{
|
||||
{
|
||||
ID: "folder1",
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
{DeviceID: device2, IntroducedBy: device1},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "folder2",
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
{DeviceID: device2, IntroducedBy: device1},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{})
|
||||
|
||||
if _, ok := wcfg.Device(device2); !ok {
|
||||
t.Error("device 2 should not have been removed")
|
||||
}
|
||||
|
||||
if !contains(wcfg.Folders()["folder1"], device2, device1) {
|
||||
t.Error("expected device 2 not to be removed from folder 1")
|
||||
}
|
||||
|
||||
if !contains(wcfg.Folders()["folder2"], device2, device1) {
|
||||
t.Error("expected device 2 not to be removed from folder 2")
|
||||
}
|
||||
|
||||
// 2. SkipIntroductionRemovals is set
|
||||
|
||||
wcfg, m = newState(config.Configuration{
|
||||
Devices: []config.DeviceConfiguration{
|
||||
{
|
||||
DeviceID: device1,
|
||||
Introducer: true,
|
||||
SkipIntroductionRemovals: true,
|
||||
},
|
||||
{
|
||||
DeviceID: device2,
|
||||
IntroducedBy: device1,
|
||||
},
|
||||
},
|
||||
Folders: []config.FolderConfiguration{
|
||||
{
|
||||
ID: "folder1",
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
{DeviceID: device2, IntroducedBy: device1},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "folder2",
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: "folder2",
|
||||
Devices: []protocol.Device{
|
||||
{
|
||||
ID: device2,
|
||||
Introducer: true,
|
||||
SkipIntroductionRemovals: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if _, ok := wcfg.Device(device2); !ok {
|
||||
t.Error("device 2 should not have been removed")
|
||||
}
|
||||
|
||||
if !contains(wcfg.Folders()["folder1"], device2, device1) {
|
||||
t.Error("expected device 2 not to be removed from folder 1")
|
||||
}
|
||||
|
||||
if !contains(wcfg.Folders()["folder2"], device2, device1) {
|
||||
t.Error("expected device 2 not to be added to folder 2")
|
||||
}
|
||||
|
||||
// Test device not being removed as it's shared without an introducer.
|
||||
|
||||
wcfg, m = newState(config.Configuration{
|
||||
Devices: []config.DeviceConfiguration{
|
||||
{
|
||||
DeviceID: device1,
|
||||
Introducer: true,
|
||||
},
|
||||
{
|
||||
DeviceID: device2,
|
||||
IntroducedBy: device1,
|
||||
},
|
||||
},
|
||||
Folders: []config.FolderConfiguration{
|
||||
{
|
||||
ID: "folder1",
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
{DeviceID: device2, IntroducedBy: device1},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "folder2",
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
{DeviceID: device2},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{})
|
||||
|
||||
if _, ok := wcfg.Device(device2); !ok {
|
||||
t.Error("device 2 should not have been removed")
|
||||
}
|
||||
|
||||
if contains(wcfg.Folders()["folder1"], device2, introducedByAnyone) {
|
||||
t.Error("expected device 2 to be removed from folder 1")
|
||||
}
|
||||
|
||||
if !contains(wcfg.Folders()["folder2"], device2, introducedByAnyone) {
|
||||
t.Error("expected device 2 not to be removed from folder 2")
|
||||
}
|
||||
|
||||
// Test device not being removed as it's shared by a different introducer.
|
||||
|
||||
wcfg, m = newState(config.Configuration{
|
||||
Devices: []config.DeviceConfiguration{
|
||||
{
|
||||
DeviceID: device1,
|
||||
Introducer: true,
|
||||
},
|
||||
{
|
||||
DeviceID: device2,
|
||||
IntroducedBy: device1,
|
||||
},
|
||||
},
|
||||
Folders: []config.FolderConfiguration{
|
||||
{
|
||||
ID: "folder1",
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
{DeviceID: device2, IntroducedBy: device1},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "folder2",
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
{DeviceID: device2, IntroducedBy: protocol.LocalDeviceID},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{})
|
||||
|
||||
if _, ok := wcfg.Device(device2); !ok {
|
||||
t.Error("device 2 should not have been removed")
|
||||
}
|
||||
|
||||
if contains(wcfg.Folders()["folder1"], device2, introducedByAnyone) {
|
||||
t.Error("expected device 2 to be removed from folder 1")
|
||||
}
|
||||
|
||||
if !contains(wcfg.Folders()["folder2"], device2, introducedByAnyone) {
|
||||
t.Error("expected device 2 not to be removed from folder 2")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIgnores(t *testing.T) {
|
||||
arrEqual := func(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
@@ -1623,7 +1993,7 @@ func TestSharedWithClearedOnDisconnect(t *testing.T) {
|
||||
t.Error("folder missing?")
|
||||
}
|
||||
|
||||
for _, id := range fdevs {
|
||||
for id := range fdevs {
|
||||
if id == device2 {
|
||||
t.Error("still there")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user