lib/model: Scan conflicts after creation (#5511)

Also unflakes and improve TestRequestRemoteRenameChanged.
This commit is contained in:
Simon Frei 2019-02-12 16:05:20 +01:00 committed by Jakob Borg
parent 5fd2cab102
commit 225c0dda80
2 changed files with 62 additions and 18 deletions

View File

@ -196,7 +196,7 @@ func (f *sendReceiveFolder) pull() bool {
changed := f.pullerIteration(ignores, folderFiles, scanChan) changed := f.pullerIteration(ignores, folderFiles, scanChan)
l.Debugln(f, "changed", changed, "on try", tries) l.Debugln(f, "changed", changed, "on try", tries+1)
if changed == 0 { if changed == 0 {
// No files were changed by the puller, so we are in // No files were changed by the puller, so we are in
@ -795,7 +795,7 @@ func (f *sendReceiveFolder) deleteFile(file protocol.FileInfo, scanChan chan<- s
// we have resolved the conflict. // we have resolved the conflict.
file.Version = file.Version.Merge(cur.Version) file.Version = file.Version.Merge(cur.Version)
err = osutil.InWritableDir(func(name string) error { err = osutil.InWritableDir(func(name string) error {
return f.moveForConflict(name, file.ModifiedBy.String()) return f.moveForConflict(name, file.ModifiedBy.String(), scanChan)
}, f.fs, file.Name) }, f.fs, file.Name)
} else if f.versioner != nil && !cur.IsSymlink() { } else if f.versioner != nil && !cur.IsSymlink() {
err = osutil.InWritableDir(f.versioner.Archive, f.fs, file.Name) err = osutil.InWritableDir(f.versioner.Archive, f.fs, file.Name)
@ -1512,7 +1512,7 @@ func (f *sendReceiveFolder) performFinish(ignores *ignore.Matcher, file, curFile
file.Version = file.Version.Merge(curFile.Version) file.Version = file.Version.Merge(curFile.Version)
err = osutil.InWritableDir(func(name string) error { err = osutil.InWritableDir(func(name string) error {
return f.moveForConflict(name, file.ModifiedBy.String()) return f.moveForConflict(name, file.ModifiedBy.String(), scanChan)
}, f.fs, file.Name) }, f.fs, file.Name)
if err != nil { if err != nil {
return err return err
@ -1736,7 +1736,7 @@ func removeAvailability(availabilities []Availability, availability Availability
return availabilities return availabilities
} }
func (f *sendReceiveFolder) moveForConflict(name string, lastModBy string) error { func (f *sendReceiveFolder) moveForConflict(name string, lastModBy string, scanChan chan<- string) error {
if strings.Contains(filepath.Base(name), ".sync-conflict-") { if strings.Contains(filepath.Base(name), ".sync-conflict-") {
l.Infoln("Conflict for", name, "which is already a conflict copy; not copying again.") l.Infoln("Conflict for", name, "which is already a conflict copy; not copying again.")
if err := f.fs.Remove(name); err != nil && !fs.IsNotExist(err) { if err := f.fs.Remove(name); err != nil && !fs.IsNotExist(err) {
@ -1777,6 +1777,9 @@ func (f *sendReceiveFolder) moveForConflict(name string, lastModBy string) error
l.Debugln(f, "globbing for conflicts", gerr) l.Debugln(f, "globbing for conflicts", gerr)
} }
} }
if err == nil {
scanChan <- newName
}
return err return err
} }

View File

@ -792,17 +792,6 @@ func TestRequestRemoteRenameChanged(t *testing.T) {
fc.sendIndexUpdate() fc.sendIndexUpdate()
select { select {
case <-done: case <-done:
done = make(chan struct{})
fc.mut.Lock()
fc.indexFn = func(folder string, fs []protocol.FileInfo) {
select {
case <-done:
t.Fatalf("More than one index update sent")
default:
}
close(done)
}
fc.mut.Unlock()
case <-time.After(10 * time.Second): case <-time.After(10 * time.Second):
t.Fatal("timed out") t.Fatal("timed out")
} }
@ -813,6 +802,42 @@ func TestRequestRemoteRenameChanged(t *testing.T) {
} }
} }
var gotA, gotB, gotConfl bool
done = make(chan struct{})
fc.mut.Lock()
fc.indexFn = func(folder string, fs []protocol.FileInfo) {
select {
case <-done:
t.Fatalf("Received more index updates than expected")
default:
}
for _, f := range fs {
switch {
case f.Name == a:
if gotA {
t.Error("Got more than one index update for", f.Name)
}
gotA = true
case f.Name == b:
if gotB {
t.Error("Got more than one index update for", f.Name)
}
gotB = true
case strings.HasPrefix(f.Name, "b.sync-conflict-"):
if gotConfl {
t.Error("Got more than one index update for conflicts of", f.Name)
}
gotConfl = true
default:
t.Error("Got unexpected file in index update", f.Name)
}
}
if gotA && gotB && gotConfl {
close(done)
}
}
fc.mut.Unlock()
fd, err := tfs.OpenFile(b, fs.OptReadWrite, 0644) fd, err := tfs.OpenFile(b, fs.OptReadWrite, 0644)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -826,11 +851,20 @@ func TestRequestRemoteRenameChanged(t *testing.T) {
// rename // rename
fc.deleteFile(a) fc.deleteFile(a)
fc.updateFile(b, 0644, protocol.FileInfoTypeFile, data[a]) fc.updateFile(b, 0644, protocol.FileInfoTypeFile, data[a])
// Make sure the remote file for b is newer and thus stays global -> local conflict
fc.mut.Lock()
for i := range fc.files {
if fc.files[i].Name == b {
fc.files[i].ModifiedS += 100
break
}
}
fc.mut.Unlock()
fc.sendIndexUpdate() fc.sendIndexUpdate()
select { select {
case <-done: case <-done:
case <-time.After(10 * time.Second): case <-time.After(10 * time.Second):
t.Fatal("timed out") t.Errorf("timed out without receiving all expected index updates")
} }
// Check outcome // Check outcome
@ -839,9 +873,16 @@ func TestRequestRemoteRenameChanged(t *testing.T) {
case path == a: case path == a:
t.Errorf(`File "a" was not removed`) t.Errorf(`File "a" was not removed`)
case path == b: case path == b:
if err := equalContents(filepath.Join(tmpDir, b), otherData); err != nil { if err := equalContents(filepath.Join(tmpDir, b), data[a]); err != nil {
t.Errorf(`Modified file "b" was overwritten`) t.Error(`File "b" has unexpected content (renamed from a on remote)`)
} }
case strings.HasPrefix(path, b+".sync-conflict-"):
if err := equalContents(filepath.Join(tmpDir, path), otherData); err != nil {
t.Error(`Sync conflict of "b" has unexptected content`)
}
case path == "." || strings.HasPrefix(path, ".stfolder"):
default:
t.Error("Found unexpected file", path)
} }
return nil return nil
}) })