This commit is contained in:
@@ -196,8 +196,8 @@ func TestRecvOnlyRevertNeeds(t *testing.T) {
|
||||
|
||||
size = m.GlobalSize("ro")
|
||||
const sizeOfDir = 128
|
||||
if size.Files != 1 || size.Bytes != sizeOfDir+int64(len(newData)) {
|
||||
t.Fatalf("Global: expected the new file to be reflected: %+v", size)
|
||||
if size.Files != 1 || size.Bytes != sizeOfDir+int64(len(oldData)) {
|
||||
t.Fatalf("Global: expected no change due to the new file: %+v", size)
|
||||
}
|
||||
size = m.LocalSize("ro")
|
||||
if size.Files != 1 || size.Bytes != sizeOfDir+int64(len(newData)) {
|
||||
@@ -230,6 +230,99 @@ func TestRecvOnlyRevertNeeds(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecvOnlyUndoChanges(t *testing.T) {
|
||||
if err := os.RemoveAll("_recvonly"); err != nil && !os.IsNotExist(err) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll("_recvonly"); err != nil && !os.IsNotExist(err) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Create some test data
|
||||
|
||||
if err := os.MkdirAll("_recvonly/.stfolder", 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
oldData := []byte("hello\n")
|
||||
knownFiles := setupKnownFiles(t, oldData)
|
||||
|
||||
// Get us a model up and running
|
||||
|
||||
m := setupROFolder()
|
||||
defer m.Stop()
|
||||
|
||||
m.fmut.Lock()
|
||||
fset := m.folderFiles["ro"]
|
||||
m.fmut.Unlock()
|
||||
folderFs := fset.MtimeFS()
|
||||
|
||||
// Send and index update for the known stuff
|
||||
|
||||
m.Index(device1, "ro", knownFiles)
|
||||
m.updateLocalsFromScanning("ro", knownFiles)
|
||||
|
||||
// Start the folder. This will cause a scan.
|
||||
|
||||
m.StartFolder("ro")
|
||||
m.ScanFolder("ro")
|
||||
|
||||
// Everything should be in sync.
|
||||
|
||||
size := m.GlobalSize("ro")
|
||||
if size.Files != 1 || size.Directories != 1 {
|
||||
t.Fatalf("Global: expected 1 file and 1 directory: %+v", size)
|
||||
}
|
||||
size = m.LocalSize("ro")
|
||||
if size.Files != 1 || size.Directories != 1 {
|
||||
t.Fatalf("Local: expected 1 file and 1 directory: %+v", size)
|
||||
}
|
||||
size = m.NeedSize("ro")
|
||||
if size.Files+size.Directories > 0 {
|
||||
t.Fatalf("Need: expected nothing: %+v", size)
|
||||
}
|
||||
size = m.ReceiveOnlyChangedSize("ro")
|
||||
if size.Files+size.Directories > 0 {
|
||||
t.Fatalf("ROChanged: expected nothing: %+v", size)
|
||||
}
|
||||
|
||||
// Create a file and modify another
|
||||
|
||||
file := "_recvonly/foo"
|
||||
if err := ioutil.WriteFile(file, []byte("hello\n"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile("_recvonly/knownDir/knownFile", []byte("bye\n"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
m.ScanFolder("ro")
|
||||
|
||||
size = m.ReceiveOnlyChangedSize("ro")
|
||||
if size.Files != 2 {
|
||||
t.Fatalf("Receive only: expected 2 files: %+v", size)
|
||||
}
|
||||
|
||||
// Remove the file again and undo the modification
|
||||
|
||||
if err := os.Remove(file); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile("_recvonly/knownDir/knownFile", oldData, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
folderFs.Chtimes("knownDir/knownFile", knownFiles[1].ModTime(), knownFiles[1].ModTime())
|
||||
|
||||
m.ScanFolder("ro")
|
||||
|
||||
size = m.ReceiveOnlyChangedSize("ro")
|
||||
if size.Files+size.Directories+size.Deleted != 0 {
|
||||
t.Fatalf("Receive only: expected all zero: %+v", size)
|
||||
}
|
||||
}
|
||||
|
||||
func setupKnownFiles(t *testing.T, data []byte) []protocol.FileInfo {
|
||||
if err := os.MkdirAll("_recvonly/knownDir", 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -2058,14 +2058,38 @@ func (m *Model) internalScanFolderSubdirs(ctx context.Context, folder string, su
|
||||
return err
|
||||
}
|
||||
|
||||
batch := newFileInfoBatch(func(fs []protocol.FileInfo) error {
|
||||
batchFn := func(fs []protocol.FileInfo) error {
|
||||
if err := runner.CheckHealth(); err != nil {
|
||||
l.Debugf("Stopping scan of folder %s due to: %s", folderCfg.Description(), err)
|
||||
return err
|
||||
}
|
||||
m.updateLocalsFromScanning(folder, fs)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
// Resolve items which are identical with the global state.
|
||||
if localFlags&protocol.FlagLocalReceiveOnly != 0 {
|
||||
oldBatchFn := batchFn // can't reference batchFn directly (recursion)
|
||||
batchFn = func(fs []protocol.FileInfo) error {
|
||||
for i := range fs {
|
||||
switch gf, ok := fset.GetGlobal(fs[i].Name); {
|
||||
case !ok:
|
||||
continue
|
||||
case gf.IsEquivalentOptional(fs[i], false, false, protocol.FlagLocalReceiveOnly):
|
||||
// What we have locally is equivalent to the global file.
|
||||
fs[i].Version = fs[i].Version.Merge(gf.Version)
|
||||
fallthrough
|
||||
case fs[i].IsDeleted() && gf.IsReceiveOnlyChanged():
|
||||
// Our item is deleted and the global item is our own
|
||||
// receive only file. We can't delete file infos, so
|
||||
// we just pretend it is a normal deleted file (nobody
|
||||
// cares about that).
|
||||
fs[i].LocalFlags &^= protocol.FlagLocalReceiveOnly
|
||||
}
|
||||
}
|
||||
return oldBatchFn(fs)
|
||||
}
|
||||
}
|
||||
batch := newFileInfoBatch(batchFn)
|
||||
|
||||
// Schedule a pull after scanning, but only if we actually detected any
|
||||
// changes.
|
||||
|
||||
Reference in New Issue
Block a user