From a596e5e2f0dcd6356f59dbedc793026c9f576756 Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Wed, 12 Feb 2020 07:35:24 +0100 Subject: [PATCH 1/3] lib/model: Consistent error return values for folder methods on model (#6325) --- lib/model/folder_recvonly_test.go | 6 +++++- lib/model/model.go | 25 ++++++++++++------------ lib/model/model_test.go | 32 +++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/lib/model/folder_recvonly_test.go b/lib/model/folder_recvonly_test.go index e2eb007260a..943efba98cb 100644 --- a/lib/model/folder_recvonly_test.go +++ b/lib/model/folder_recvonly_test.go @@ -48,7 +48,11 @@ func TestRecvOnlyRevertDeletes(t *testing.T) { m.Index(device1, "ro", knownFiles) f.updateLocalsFromScanning(knownFiles) - size := globalSize(t, m, "ro") + m.fmut.RLock() + snap := m.folderFiles["ro"].Snapshot() + m.fmut.RUnlock() + size := snap.GlobalSize() + snap.Release() if size.Files != 1 || size.Directories != 1 { t.Fatalf("Global: expected 1 file and 1 directory: %+v", size) } diff --git a/lib/model/model.go b/lib/model/model.go index f0b6b0e2dd1..217c7294cc9 100644 --- a/lib/model/model.go +++ b/lib/model/model.go @@ -840,10 +840,11 @@ func (m *model) Completion(device protocol.DeviceID, folder string) FolderComple // DBSnapshot returns a snapshot of the database content relevant to the given folder. func (m *model) DBSnapshot(folder string) (*db.Snapshot, error) { m.fmut.RLock() - rf, ok := m.folderFiles[folder] + err := m.checkFolderRunningLocked(folder) + rf := m.folderFiles[folder] m.fmut.RUnlock() - if !ok { - return nil, errFolderMissing + if err != nil { + return nil, err } return rf.Snapshot(), nil } @@ -2319,10 +2320,11 @@ func (m *model) GlobalDirectoryTree(folder, prefix string, levels int, dirsonly func (m *model) GetFolderVersions(folder string) (map[string][]versioner.FileVersion, error) { m.fmut.RLock() - ver, ok := m.folderVersioners[folder] + err := m.checkFolderRunningLocked(folder) + ver := m.folderVersioners[folder] m.fmut.RUnlock() - if !ok { - return nil, errFolderMissing + if err != nil { + return nil, err } if ver == nil { return nil, errNoVersioner @@ -2332,16 +2334,13 @@ func (m *model) GetFolderVersions(folder string) (map[string][]versioner.FileVer } func (m *model) RestoreFolderVersions(folder string, versions map[string]time.Time) (map[string]string, error) { - fcfg, ok := m.cfg.Folder(folder) - if !ok { - return nil, errFolderMissing - } - m.fmut.RLock() + err := m.checkFolderRunningLocked(folder) + fcfg := m.folderCfgs[folder] ver := m.folderVersioners[folder] m.fmut.RUnlock() - if !ok { - return nil, errFolderMissing + if err != nil { + return nil, err } if ver == nil { return nil, errNoVersioner diff --git a/lib/model/model_test.go b/lib/model/model_test.go index 62d9e1ff6f5..36d3e1cded0 100644 --- a/lib/model/model_test.go +++ b/lib/model/model_test.go @@ -3479,3 +3479,35 @@ func TestNewLimitedRequestResponse(t *testing.T) { t.Error("Bytes weren't returned in a timely fashion") } } + +func TestFolderAPIErrors(t *testing.T) { + wcfg, fcfg := tmpDefaultWrapper() + fcfg.Paused = true + wcfg.SetFolder(fcfg) + m := setupModel(wcfg) + defer cleanupModel(m) + + methods := []func(folder string) error{ + m.ScanFolder, + func(folder string) error { + return m.ScanFolderSubdirs(folder, nil) + }, + func(folder string) error { + _, err := m.GetFolderVersions(folder) + return err + }, + func(folder string) error { + _, err := m.RestoreFolderVersions(folder, nil) + return err + }, + } + + for i, method := range methods { + if err := method(fcfg.ID); err != ErrFolderPaused { + t.Errorf(`Expected "%v", got "%v" (method no %v)`, ErrFolderPaused, err, i) + } + if err := method("notexisting"); err != errFolderMissing { + t.Errorf(`Expected "%v", got "%v" (method no %v)`, errFolderMissing, err, i) + } + } +} From b84aa114be02e4827080380e9356b4fe6b2ffde4 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Wed, 12 Feb 2020 07:45:30 +0100 Subject: [PATCH 2/3] gui, man, authors: Update docs, translations, and contributors --- man/stdiscosrv.1 | 2 +- man/strelaysrv.1 | 2 +- man/syncthing-bep.7 | 2 +- man/syncthing-config.5 | 2 +- man/syncthing-device-ids.7 | 2 +- man/syncthing-event-api.7 | 2 +- man/syncthing-faq.7 | 2 +- man/syncthing-globaldisco.7 | 2 +- man/syncthing-localdisco.7 | 2 +- man/syncthing-networking.7 | 2 +- man/syncthing-relay.7 | 6 +++--- man/syncthing-rest-api.7 | 2 +- man/syncthing-security.7 | 2 +- man/syncthing-stignore.5 | 4 ++-- man/syncthing-versioning.7 | 2 +- man/syncthing.1 | 2 +- 16 files changed, 19 insertions(+), 19 deletions(-) diff --git a/man/stdiscosrv.1 b/man/stdiscosrv.1 index 94e7597baf0..ca8c2fb61c4 100644 --- a/man/stdiscosrv.1 +++ b/man/stdiscosrv.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "STDISCOSRV" "1" "Feb 02, 2020" "v1" "Syncthing" +.TH "STDISCOSRV" "1" "Feb 10, 2020" "v1" "Syncthing" .SH NAME stdiscosrv \- Syncthing Discovery Server . diff --git a/man/strelaysrv.1 b/man/strelaysrv.1 index 6766547f450..e451e96bec2 100644 --- a/man/strelaysrv.1 +++ b/man/strelaysrv.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "STRELAYSRV" "1" "Feb 02, 2020" "v1" "Syncthing" +.TH "STRELAYSRV" "1" "Feb 10, 2020" "v1" "Syncthing" .SH NAME strelaysrv \- Syncthing Relay Server . diff --git a/man/syncthing-bep.7 b/man/syncthing-bep.7 index fe6be0c7437..7250e42117e 100644 --- a/man/syncthing-bep.7 +++ b/man/syncthing-bep.7 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "SYNCTHING-BEP" "7" "Feb 02, 2020" "v1" "Syncthing" +.TH "SYNCTHING-BEP" "7" "Feb 10, 2020" "v1" "Syncthing" .SH NAME syncthing-bep \- Block Exchange Protocol v1 . diff --git a/man/syncthing-config.5 b/man/syncthing-config.5 index 20243aca5d8..6b3b988d167 100644 --- a/man/syncthing-config.5 +++ b/man/syncthing-config.5 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "SYNCTHING-CONFIG" "5" "Feb 02, 2020" "v1" "Syncthing" +.TH "SYNCTHING-CONFIG" "5" "Feb 10, 2020" "v1" "Syncthing" .SH NAME syncthing-config \- Syncthing Configuration . diff --git a/man/syncthing-device-ids.7 b/man/syncthing-device-ids.7 index 17d36c028a7..c161f0e6f26 100644 --- a/man/syncthing-device-ids.7 +++ b/man/syncthing-device-ids.7 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "SYNCTHING-DEVICE-IDS" "7" "Feb 02, 2020" "v1" "Syncthing" +.TH "SYNCTHING-DEVICE-IDS" "7" "Feb 10, 2020" "v1" "Syncthing" .SH NAME syncthing-device-ids \- Understanding Device IDs . diff --git a/man/syncthing-event-api.7 b/man/syncthing-event-api.7 index 76ea797c3b7..5772cbf2f8d 100644 --- a/man/syncthing-event-api.7 +++ b/man/syncthing-event-api.7 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "SYNCTHING-EVENT-API" "7" "Feb 02, 2020" "v1" "Syncthing" +.TH "SYNCTHING-EVENT-API" "7" "Feb 10, 2020" "v1" "Syncthing" .SH NAME syncthing-event-api \- Event API . diff --git a/man/syncthing-faq.7 b/man/syncthing-faq.7 index 70199fc7391..65ec13c5d8d 100644 --- a/man/syncthing-faq.7 +++ b/man/syncthing-faq.7 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "SYNCTHING-FAQ" "7" "Feb 02, 2020" "v1" "Syncthing" +.TH "SYNCTHING-FAQ" "7" "Feb 10, 2020" "v1" "Syncthing" .SH NAME syncthing-faq \- Frequently Asked Questions . diff --git a/man/syncthing-globaldisco.7 b/man/syncthing-globaldisco.7 index d1e81837ba1..d1d5ce38b57 100644 --- a/man/syncthing-globaldisco.7 +++ b/man/syncthing-globaldisco.7 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "SYNCTHING-GLOBALDISCO" "7" "Feb 02, 2020" "v1" "Syncthing" +.TH "SYNCTHING-GLOBALDISCO" "7" "Feb 10, 2020" "v1" "Syncthing" .SH NAME syncthing-globaldisco \- Global Discovery Protocol v3 . diff --git a/man/syncthing-localdisco.7 b/man/syncthing-localdisco.7 index d2018c75546..32cb353638b 100644 --- a/man/syncthing-localdisco.7 +++ b/man/syncthing-localdisco.7 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "SYNCTHING-LOCALDISCO" "7" "Feb 02, 2020" "v1" "Syncthing" +.TH "SYNCTHING-LOCALDISCO" "7" "Feb 10, 2020" "v1" "Syncthing" .SH NAME syncthing-localdisco \- Local Discovery Protocol v4 . diff --git a/man/syncthing-networking.7 b/man/syncthing-networking.7 index 8e23ee44a9b..c6be39c89fb 100644 --- a/man/syncthing-networking.7 +++ b/man/syncthing-networking.7 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "SYNCTHING-NETWORKING" "7" "Feb 02, 2020" "v1" "Syncthing" +.TH "SYNCTHING-NETWORKING" "7" "Feb 10, 2020" "v1" "Syncthing" .SH NAME syncthing-networking \- Firewall Setup . diff --git a/man/syncthing-relay.7 b/man/syncthing-relay.7 index d73d8b9dec2..ff23182b53c 100644 --- a/man/syncthing-relay.7 +++ b/man/syncthing-relay.7 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "SYNCTHING-RELAY" "7" "Feb 02, 2020" "v1" "Syncthing" +.TH "SYNCTHING-RELAY" "7" "Feb 10, 2020" "v1" "Syncthing" .SH NAME syncthing-relay \- Relay Protocol v1 . @@ -227,7 +227,7 @@ _ .SH SESSION MODE .sp The first and only message the client sends in the session mode is the -SessionInvitation message which contains the session key identifying which +JoinSessionRequest message which contains the session key identifying which session you are trying to join. The relay responds with one of the following Response messages: .INDENT 0.0 @@ -578,7 +578,7 @@ Empty/all zero IP should be replaced with the relay’s public IP address that was used when establishing the protocol mode connection. .TP .B : Port -An optional port on which the relay server is expecting you to connect, +The port on which the relay server is expecting you to connect, in order to start a connection in session mode. .TP .B : Server Socket diff --git a/man/syncthing-rest-api.7 b/man/syncthing-rest-api.7 index 2098ed5b4f3..4838aa23156 100644 --- a/man/syncthing-rest-api.7 +++ b/man/syncthing-rest-api.7 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "SYNCTHING-REST-API" "7" "Feb 02, 2020" "v1" "Syncthing" +.TH "SYNCTHING-REST-API" "7" "Feb 10, 2020" "v1" "Syncthing" .SH NAME syncthing-rest-api \- REST API . diff --git a/man/syncthing-security.7 b/man/syncthing-security.7 index 03181d88e5a..bda73a55a20 100644 --- a/man/syncthing-security.7 +++ b/man/syncthing-security.7 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "SYNCTHING-SECURITY" "7" "Feb 02, 2020" "v1" "Syncthing" +.TH "SYNCTHING-SECURITY" "7" "Feb 10, 2020" "v1" "Syncthing" .SH NAME syncthing-security \- Security Principles . diff --git a/man/syncthing-stignore.5 b/man/syncthing-stignore.5 index a2cab364bfc..f2f53c9c205 100644 --- a/man/syncthing-stignore.5 +++ b/man/syncthing-stignore.5 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "SYNCTHING-STIGNORE" "5" "Feb 02, 2020" "v1" "Syncthing" +.TH "SYNCTHING-STIGNORE" "5" "Feb 10, 2020" "v1" "Syncthing" .SH NAME syncthing-stignore \- Prevent files from being synchronized to other nodes . @@ -43,7 +43,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .UNINDENT .SH DESCRIPTION .sp -If some files should not be synchronized to other devices, a file called +If some files should not be synchronized to (or from) other devices, a file called \fB\&.stignore\fP can be created containing file patterns to ignore. The \fB\&.stignore\fP file must be placed in the root of the folder. The \fB\&.stignore\fP file itself will never be synced to other devices, although it can diff --git a/man/syncthing-versioning.7 b/man/syncthing-versioning.7 index 34597df7df0..42ee687da21 100644 --- a/man/syncthing-versioning.7 +++ b/man/syncthing-versioning.7 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "SYNCTHING-VERSIONING" "7" "Feb 02, 2020" "v1" "Syncthing" +.TH "SYNCTHING-VERSIONING" "7" "Feb 10, 2020" "v1" "Syncthing" .SH NAME syncthing-versioning \- Keep automatic backups of deleted files by other nodes . diff --git a/man/syncthing.1 b/man/syncthing.1 index 7e155f2a443..a70563d1856 100644 --- a/man/syncthing.1 +++ b/man/syncthing.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "SYNCTHING" "1" "Feb 02, 2020" "v1" "Syncthing" +.TH "SYNCTHING" "1" "Feb 10, 2020" "v1" "Syncthing" .SH NAME syncthing \- Syncthing . From 0df39ddc72bc9d7dc931de0e7410b0a4d47df0a2 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Wed, 12 Feb 2020 07:47:05 +0100 Subject: [PATCH 3/3] lib/fs, lib/model: Rewrite RecvOnly tests (#6318) During some other work I discovered these tests weren't great, so I've rewritten them to be a little better. The real changes here are: - Don't play games with not starting the folder and such, and don't construct a fake folder instance -- just use the one the model has. The folder starts and scans but the folder contents are empty at this point so that's fine. - Use a fakefs instead of a temp dir. - To support the above, implement a fakefs option `?content=true` to make the fakefs actually retain written content. Use sparingly, obviously, but it means the fakefs can usually be used instead of an on disk real directory. --- lib/fs/fakefs.go | 43 +++++++++++-- lib/fs/fakefs_test.go | 29 +++++++++ lib/model/folder_recvonly_test.go | 103 ++++++++++++++---------------- lib/model/testutils_test.go | 8 +++ 4 files changed, 123 insertions(+), 60 deletions(-) diff --git a/lib/fs/fakefs.go b/lib/fs/fakefs.go index bf756707a22..8a102bba757 100644 --- a/lib/fs/fakefs.go +++ b/lib/fs/fakefs.go @@ -52,9 +52,10 @@ const randomBlockShift = 14 // 128k // - Two fakefs:s pointing at the same root path see the same files. // type fakefs struct { - mut sync.Mutex - root *fakeEntry - insens bool + mut sync.Mutex + root *fakeEntry + insens bool + withContent bool } var ( @@ -93,9 +94,9 @@ func newFakeFilesystem(root string) *fakefs { sizeavg, _ := strconv.Atoi(params.Get("sizeavg")) seed, _ := strconv.Atoi(params.Get("seed")) - if params.Get("insens") == "true" { - fs.insens = true - } + fs.insens = params.Get("insens") == "true" + fs.withContent = params.Get("content") == "true" + if sizeavg == 0 { sizeavg = 1 << 20 } @@ -151,6 +152,7 @@ type fakeEntry struct { gid int mtime time.Time children map[string]*fakeEntry + content []byte } func (fs *fakefs) entryForName(name string) *fakeEntry { @@ -227,6 +229,10 @@ func (fs *fakefs) create(name string) (*fakeEntry, error) { entry.size = 0 entry.mtime = time.Now() entry.mode = 0666 + entry.content = nil + if fs.withContent { + entry.content = make([]byte, 0) + } return entry, nil } @@ -246,6 +252,10 @@ func (fs *fakefs) create(name string) (*fakeEntry, error) { base = UnicodeLowercase(base) } + if fs.withContent { + new.content = make([]byte, 0) + } + entry.children[base] = new return new, nil } @@ -417,6 +427,9 @@ func (fs *fakefs) OpenFile(name string, flags int, mode FileMode) (File, error) mode: mode, mtime: time.Now(), } + if fs.withContent { + newEntry.content = make([]byte, 0) + } entry.children[key] = newEntry return &fakeFile{fakeEntry: newEntry}, nil @@ -660,6 +673,12 @@ func (f *fakeFile) readShortAt(p []byte, offs int64) (int, error) { return 0, io.EOF } + if f.content != nil { + n := copy(p, f.content[int(offs):]) + f.offset = offs + int64(n) + return n, nil + } + // Lazily calculate our main seed, a simple 64 bit FNV hash our file // name. if f.seed == 0 { @@ -746,6 +765,15 @@ func (f *fakeFile) WriteAt(p []byte, off int64) (int, error) { return 0, errors.New("is a directory") } + if f.content != nil { + if len(f.content) < int(off)+len(p) { + newc := make([]byte, int(off)+len(p)) + copy(newc, f.content) + f.content = newc + } + copy(f.content[int(off):], p) + } + f.rng = nil f.offset = off + int64(len(p)) if f.offset > f.size { @@ -765,6 +793,9 @@ func (f *fakeFile) Truncate(size int64) error { f.mut.Lock() defer f.mut.Unlock() + if f.content != nil { + f.content = f.content[:int(size)] + } f.rng = nil f.size = size if f.offset > size { diff --git a/lib/fs/fakefs_test.go b/lib/fs/fakefs_test.go index 7040b35c945..d7b897ae636 100644 --- a/lib/fs/fakefs_test.go +++ b/lib/fs/fakefs_test.go @@ -896,6 +896,35 @@ func testFakeFSCreateInsens(t *testing.T, fs Filesystem) { assertDir(t, fs, "/", []string{"FOO"}) } +func TestReadWriteContent(t *testing.T) { + fs := newFakeFilesystem("foo?content=true") + fd, err := fs.Create("file") + if err != nil { + t.Fatal(err) + } + + if _, err := fd.Write([]byte("foo")); err != nil { + t.Fatal(err) + } + if _, err := fd.WriteAt([]byte("bar"), 5); err != nil { + t.Fatal(err) + } + expected := []byte("foo\x00\x00bar") + + buf := make([]byte, len(expected)-1) + n, err := fd.ReadAt(buf, 1) // note offset one byte + if err != nil { + t.Fatal(err) + } + if n != len(expected)-1 { + t.Fatal("wrong number of bytes read") + } + if !bytes.Equal(buf[:n], expected[1:]) { + fmt.Printf("%d %q\n", n, buf[:n]) + t.Error("wrong data in file") + } +} + func cleanup(fs Filesystem) error { filenames, _ := fs.DirNames("/") for _, filename := range filenames { diff --git a/lib/model/folder_recvonly_test.go b/lib/model/folder_recvonly_test.go index 943efba98cb..a3d48b6dc5a 100644 --- a/lib/model/folder_recvonly_test.go +++ b/lib/model/folder_recvonly_test.go @@ -9,8 +9,6 @@ package model import ( "bytes" "context" - "io/ioutil" - "path/filepath" "testing" "time" @@ -28,18 +26,18 @@ func TestRecvOnlyRevertDeletes(t *testing.T) { // Get us a model up and running - m, f := setupROFolder() + m, f := setupROFolder(t) ffs := f.Filesystem() - defer cleanupModelAndRemoveDir(m, ffs.URI()) + defer cleanupModel(m) // Create some test data for _, dir := range []string{".stfolder", "ignDir", "unknownDir"} { must(t, ffs.MkdirAll(dir, 0755)) } - must(t, ioutil.WriteFile(filepath.Join(ffs.URI(), "ignDir/ignFile"), []byte("hello\n"), 0644)) - must(t, ioutil.WriteFile(filepath.Join(ffs.URI(), "unknownDir/unknownFile"), []byte("hello\n"), 0644)) - must(t, ioutil.WriteFile(filepath.Join(ffs.URI(), ".stignore"), []byte("ignDir\n"), 0644)) + must(t, writeFile(ffs, "ignDir/ignFile", []byte("hello\n"), 0644)) + must(t, writeFile(ffs, "unknownDir/unknownFile", []byte("hello\n"), 0644)) + must(t, writeFile(ffs, ".stignore", []byte("ignDir\n"), 0644)) knownFiles := setupKnownFiles(t, ffs, []byte("hello\n")) @@ -57,10 +55,9 @@ func TestRecvOnlyRevertDeletes(t *testing.T) { t.Fatalf("Global: expected 1 file and 1 directory: %+v", size) } - // Start the folder. This will cause a scan, should discover the other stuff in the folder + // Scan, should discover the other stuff in the folder - m.startFolder("ro") - m.ScanFolder("ro") + must(t, m.ScanFolder("ro")) // We should now have two files and two directories. @@ -113,9 +110,9 @@ func TestRecvOnlyRevertNeeds(t *testing.T) { // Get us a model up and running - m, f := setupROFolder() + m, f := setupROFolder(t) ffs := f.Filesystem() - defer cleanupModelAndRemoveDir(m, ffs.URI()) + defer cleanupModel(m) // Create some test data @@ -128,10 +125,9 @@ func TestRecvOnlyRevertNeeds(t *testing.T) { m.Index(device1, "ro", knownFiles) f.updateLocalsFromScanning(knownFiles) - // Start the folder. This will cause a scan. + // Scan the folder. - m.startFolder("ro") - m.ScanFolder("ro") + must(t, m.ScanFolder("ro")) // Everything should be in sync. @@ -155,7 +151,7 @@ func TestRecvOnlyRevertNeeds(t *testing.T) { // Update the file. newData := []byte("totally different data\n") - must(t, ioutil.WriteFile(filepath.Join(ffs.URI(), "knownDir/knownFile"), newData, 0644)) + must(t, writeFile(ffs, "knownDir/knownFile", newData, 0644)) // Rescan. @@ -200,13 +196,11 @@ func TestRecvOnlyRevertNeeds(t *testing.T) { } func TestRecvOnlyUndoChanges(t *testing.T) { - testOs := &fatalOs{t} - // Get us a model up and running - m, f := setupROFolder() + m, f := setupROFolder(t) ffs := f.Filesystem() - defer cleanupModelAndRemoveDir(m, ffs.URI()) + defer cleanupModel(m) // Create some test data @@ -214,20 +208,14 @@ func TestRecvOnlyUndoChanges(t *testing.T) { oldData := []byte("hello\n") knownFiles := setupKnownFiles(t, ffs, oldData) - m.fmut.Lock() - fset := m.folderFiles["ro"] - m.fmut.Unlock() - folderFs := fset.MtimeFS() - - // Send and index update for the known stuff + // Send an index update for the known stuff m.Index(device1, "ro", knownFiles) f.updateLocalsFromScanning(knownFiles) - // Start the folder. This will cause a scan. + // Scan the folder. - m.startFolder("ro") - m.ScanFolder("ro") + must(t, m.ScanFolder("ro")) // Everything should be in sync. @@ -250,12 +238,11 @@ func TestRecvOnlyUndoChanges(t *testing.T) { // Create a file and modify another - file := filepath.Join(ffs.URI(), "foo") - must(t, ioutil.WriteFile(file, []byte("hello\n"), 0644)) + const file = "foo" + must(t, writeFile(ffs, file, []byte("hello\n"), 0644)) + must(t, writeFile(ffs, "knownDir/knownFile", []byte("bye\n"), 0644)) - must(t, ioutil.WriteFile(filepath.Join(ffs.URI(), "knownDir/knownFile"), []byte("bye\n"), 0644)) - - m.ScanFolder("ro") + must(t, m.ScanFolder("ro")) size = receiveOnlyChangedSize(t, m, "ro") if size.Files != 2 { @@ -264,11 +251,11 @@ func TestRecvOnlyUndoChanges(t *testing.T) { // Remove the file again and undo the modification - testOs.Remove(file) - must(t, ioutil.WriteFile(filepath.Join(ffs.URI(), "knownDir/knownFile"), oldData, 0644)) - folderFs.Chtimes("knownDir/knownFile", knownFiles[1].ModTime(), knownFiles[1].ModTime()) + must(t, ffs.Remove(file)) + must(t, writeFile(ffs, "knownDir/knownFile", oldData, 0644)) + must(t, ffs.Chtimes("knownDir/knownFile", knownFiles[1].ModTime(), knownFiles[1].ModTime())) - m.ScanFolder("ro") + must(t, m.ScanFolder("ro")) size = receiveOnlyChangedSize(t, m, "ro") if size.Files+size.Directories+size.Deleted != 0 { @@ -280,7 +267,7 @@ func setupKnownFiles(t *testing.T, ffs fs.Filesystem, data []byte) []protocol.Fi t.Helper() must(t, ffs.MkdirAll("knownDir", 0755)) - must(t, ioutil.WriteFile(filepath.Join(ffs.URI(), "knownDir/knownFile"), data, 0644)) + must(t, writeFile(ffs, "knownDir/knownFile", data, 0644)) t0 := time.Now().Add(-1 * time.Minute) must(t, ffs.Chtimes("knownDir/knownFile", t0, t0)) @@ -314,30 +301,38 @@ func setupKnownFiles(t *testing.T, ffs fs.Filesystem, data []byte) []protocol.Fi return knownFiles } -func setupROFolder() (*model, *sendOnlyFolder) { +func setupROFolder(t *testing.T) (*model, *receiveOnlyFolder) { + t.Helper() + w := createTmpWrapper(defaultCfg) - fcfg := testFolderConfigTmp() + fcfg := testFolderConfigFake() fcfg.ID = "ro" + fcfg.Label = "ro" fcfg.Type = config.FolderTypeReceiveOnly w.SetFolder(fcfg) m := newModel(w, myID, "syncthing", "dev", db.NewLowlevel(backend.OpenMemory()), nil) - m.ServeBackground() - - // Folder should only be added, not started. - m.removeFolder(fcfg) - m.addFolder(fcfg) + must(t, m.ScanFolder("ro")) m.fmut.RLock() - f := &sendOnlyFolder{ - folder: folder{ - stateTracker: newStateTracker(fcfg.ID, m.evLogger), - fset: m.folderFiles[fcfg.ID], - FolderConfiguration: fcfg, - }, - } - m.fmut.RUnlock() + defer m.fmut.RUnlock() + f := m.folderRunners["ro"].(*receiveOnlyFolder) return m, f } + +func writeFile(fs fs.Filesystem, filename string, data []byte, perm fs.FileMode) error { + fd, err := fs.Create(filename) + if err != nil { + return err + } + _, err = fd.Write(data) + if err != nil { + return err + } + if err := fd.Close(); err != nil { + return err + } + return fs.Chmod(filename, perm) +} diff --git a/lib/model/testutils_test.go b/lib/model/testutils_test.go index d2c662d4f4f..eada47020a7 100644 --- a/lib/model/testutils_test.go +++ b/lib/model/testutils_test.go @@ -18,6 +18,7 @@ import ( "github.com/syncthing/syncthing/lib/events" "github.com/syncthing/syncthing/lib/fs" "github.com/syncthing/syncthing/lib/protocol" + "github.com/syncthing/syncthing/lib/rand" ) var ( @@ -86,6 +87,13 @@ func testFolderConfig(path string) config.FolderConfiguration { return cfg } +func testFolderConfigFake() config.FolderConfiguration { + cfg := config.NewFolderConfiguration(myID, "default", "default", fs.FilesystemTypeFake, rand.String(32)+"?content=true") + cfg.FSWatcherEnabled = false + cfg.Devices = append(cfg.Devices, config.FolderDeviceConfiguration{DeviceID: device1}) + return cfg +} + func setupModelWithConnection() (*model, *fakeConnection, config.FolderConfiguration) { w, fcfg := tmpDefaultWrapper() m, fc := setupModelWithConnectionFromWrapper(w)