From 0b03b6a9ec5fc690796fa66d7a3b04e26cf8cece Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Fri, 11 Jan 2019 13:56:05 +0100 Subject: [PATCH] lib/model: Improve filesystem operations during tests (fixes #5422) * lib/fs, lib/model: Improve filesystem operations during tests (fixes #5422) Introduces MustFilesystem that panics on errors and should be used for operations during testing which must never fail. Create temporary directories outside of testdata. * don't do a filesystem, just a wrapper around os for testing * fix copyright --- lib/model/folder_recvonly_test.go | 75 ++----- lib/model/folder_sendrecv_test.go | 32 +-- lib/model/model_test.go | 325 +++++++++++++++++----------- lib/model/progressemitter_test.go | 9 +- lib/model/requests_test.go | 84 ++++--- lib/model/sharedpullerstate_test.go | 9 +- lib/model/testos_test.go | 82 +++++++ 7 files changed, 380 insertions(+), 236 deletions(-) create mode 100644 lib/model/testos_test.go diff --git a/lib/model/folder_recvonly_test.go b/lib/model/folder_recvonly_test.go index 1b73322be..286ad5727 100644 --- a/lib/model/folder_recvonly_test.go +++ b/lib/model/folder_recvonly_test.go @@ -22,29 +22,19 @@ import ( ) func TestRecvOnlyRevertDeletes(t *testing.T) { + testOs := &fatalOs{t} + // Make sure that we delete extraneous files and directories when we hit // Revert. - 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) - } - }() + testOs.RemoveAll("_recvonly") + defer testOs.RemoveAll("_recvonly") // Create some test data - if err := os.MkdirAll("_recvonly/.stfolder", 0755); err != nil { - t.Fatal(err) - } - if err := os.MkdirAll("_recvonly/ignDir", 0755); err != nil { - t.Fatal(err) - } - if err := os.MkdirAll("_recvonly/unknownDir", 0755); err != nil { - t.Fatal(err) - } + testOs.MkdirAll("_recvonly/.stfolder", 0755) + testOs.MkdirAll("_recvonly/ignDir", 0755) + testOs.MkdirAll("_recvonly/unknownDir", 0755) if err := ioutil.WriteFile("_recvonly/ignDir/ignFile", []byte("hello\n"), 0644); err != nil { t.Fatal(err) } @@ -125,23 +115,17 @@ func TestRecvOnlyRevertDeletes(t *testing.T) { } func TestRecvOnlyRevertNeeds(t *testing.T) { + testOs := &fatalOs{t} + // Make sure that a new file gets picked up and considered latest, then // gets considered old when we hit Revert. - 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) - } - }() + testOs.RemoveAll("_recvonly") + defer testOs.RemoveAll("_recvonly") // Create some test data - if err := os.MkdirAll("_recvonly/.stfolder", 0755); err != nil { - t.Fatal(err) - } + testOs.MkdirAll("_recvonly/.stfolder", 0755) oldData := []byte("hello\n") knownFiles := setupKnownFiles(t, oldData) @@ -231,20 +215,14 @@ 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) - } - }() + testOs := &fatalOs{t} + + testOs.RemoveAll("_recvonly") + defer testOs.RemoveAll("_recvonly") // Create some test data - if err := os.MkdirAll("_recvonly/.stfolder", 0755); err != nil { - t.Fatal(err) - } + testOs.MkdirAll("_recvonly/.stfolder", 0755) oldData := []byte("hello\n") knownFiles := setupKnownFiles(t, oldData) @@ -307,9 +285,7 @@ func TestRecvOnlyUndoChanges(t *testing.T) { // Remove the file again and undo the modification - if err := os.Remove(file); err != nil { - t.Fatal(err) - } + testOs.Remove(file) if err := ioutil.WriteFile("_recvonly/knownDir/knownFile", oldData, 0644); err != nil { t.Fatal(err) } @@ -324,22 +300,17 @@ func TestRecvOnlyUndoChanges(t *testing.T) { } func setupKnownFiles(t *testing.T, data []byte) []protocol.FileInfo { - if err := os.MkdirAll("_recvonly/knownDir", 0755); err != nil { - t.Fatal(err) - } + testOs := &fatalOs{t} + + testOs.MkdirAll("_recvonly/knownDir", 0755) if err := ioutil.WriteFile("_recvonly/knownDir/knownFile", data, 0644); err != nil { t.Fatal(err) } t0 := time.Now().Add(-1 * time.Minute) - if err := os.Chtimes("_recvonly/knownDir/knownFile", t0, t0); err != nil { - t.Fatal(err) - } + testOs.Chtimes("_recvonly/knownDir/knownFile", t0, t0) - fi, err := os.Stat("_recvonly/knownDir/knownFile") - if err != nil { - t.Fatal(err) - } + fi, _ := testOs.Stat("_recvonly/knownDir/knownFile") blocks, _ := scanner.Blocks(context.TODO(), bytes.NewReader(data), protocol.BlockSize(int64(len(data))), int64(len(data)), nil, true) knownFiles := []protocol.FileInfo{ { diff --git a/lib/model/folder_sendrecv_test.go b/lib/model/folder_sendrecv_test.go index e0f222c49..58a31134e 100644 --- a/lib/model/folder_sendrecv_test.go +++ b/lib/model/folder_sendrecv_test.go @@ -196,6 +196,8 @@ func TestHandleFileWithTemp(t *testing.T) { } func TestCopierFinder(t *testing.T) { + testOs := &fatalOs{t} + // After diff between required and existing we should: // Copy: 1, 2, 3, 4, 6, 7, 8 // Since there is no existing file, nor a temp file @@ -204,11 +206,8 @@ func TestCopierFinder(t *testing.T) { // Pull: 1, 5, 6, 8 tempFile := filepath.Join("testdata", fs.TempName("file2")) - err := os.Remove(tempFile) - if err != nil && !os.IsNotExist(err) { - t.Error(err) - } - defer os.Remove(tempFile) + testOs.Remove(tempFile) + defer testOs.Remove(tempFile) existingBlocks := []int{0, 2, 3, 4, 0, 0, 7, 0} existingFile := setUpFile(fs.TempName("file"), existingBlocks) @@ -273,6 +272,8 @@ func TestCopierFinder(t *testing.T) { } func TestWeakHash(t *testing.T) { + testOs := &fatalOs{t} + tempFile := filepath.Join("testdata", fs.TempName("weakhash")) var shift int64 = 10 var size int64 = 1 << 20 @@ -284,19 +285,16 @@ func TestWeakHash(t *testing.T) { cleanup := func() { for _, path := range []string{tempFile, "testdata/weakhash"} { - os.Remove(path) + testOs.Remove(path) } } cleanup() defer cleanup() - f, err := os.Create("testdata/weakhash") - if err != nil { - t.Error(err) - } + f, _ := testOs.Create("testdata/weakhash") defer f.Close() - _, err = io.CopyN(f, rand.Reader, size) + _, err := io.CopyN(f, rand.Reader, size) if err != nil { t.Error(err) } @@ -373,9 +371,7 @@ func TestWeakHash(t *testing.T) { } finish.fd.Close() - if err := os.Remove(tempFile); err != nil && !os.IsNotExist(err) { - t.Error(err) - } + testOs.Remove(tempFile) // Test 2 - using weak hash, expectPulls blocks pulled. fo.WeakHashThresholdPct = -1 @@ -438,8 +434,10 @@ func TestCopierCleanup(t *testing.T) { } func TestDeregisterOnFailInCopy(t *testing.T) { + testOs := &fatalOs{t} + file := setUpFile("filex", []int{0, 2, 0, 0, 5, 0, 0, 8}) - defer os.Remove("testdata/" + fs.TempName("filex")) + defer testOs.Remove("testdata/" + fs.TempName("filex")) db := db.OpenMemory() @@ -530,8 +528,10 @@ func TestDeregisterOnFailInCopy(t *testing.T) { } func TestDeregisterOnFailInPull(t *testing.T) { + testOs := &fatalOs{t} + file := setUpFile("filex", []int{0, 2, 0, 0, 5, 0, 0, 8}) - defer os.Remove("testdata/" + fs.TempName("filex")) + defer testOs.Remove("testdata/" + fs.TempName("filex")) db := db.OpenMemory() m := NewModel(defaultCfgWrapper, protocol.LocalDeviceID, "syncthing", "dev", db, nil) diff --git a/lib/model/model_test.go b/lib/model/model_test.go index 6b909db6f..fbb521b7e 100644 --- a/lib/model/model_test.go +++ b/lib/model/model_test.go @@ -74,7 +74,7 @@ func init() { }, }, Options: config.OptionsConfiguration{ - DefaultFolderPath: "testdata", + DefaultFolderPath: ".", }, } } @@ -114,7 +114,7 @@ func init() { func TestMain(m *testing.M) { tmpLocation = "/tmp" if runtime.GOOS == "windows" { - tmpLocation = filepath.Join("testdata", "tmp") + tmpLocation = "test-tmp" if err := os.MkdirAll(tmpLocation, 0777); err != nil { panic(err) } @@ -515,6 +515,8 @@ func BenchmarkRequestOut(b *testing.B) { } func BenchmarkRequestInSingleFile(b *testing.B) { + testOs := &fatalOs{b} + db := db.OpenMemory() m := NewModel(defaultCfgWrapper, protocol.LocalDeviceID, "syncthing", "dev", db, nil) m.AddFolder(defaultFolderConfig) @@ -524,9 +526,9 @@ func BenchmarkRequestInSingleFile(b *testing.B) { buf := make([]byte, 128<<10) rand.Read(buf) - os.RemoveAll("testdata/request") - defer os.RemoveAll("testdata/request") - os.MkdirAll("testdata/request/for/a/file/in/a/couple/of/dirs", 0755) + testOs.RemoveAll("testdata/request") + defer testOs.RemoveAll("testdata/request") + testOs.MkdirAll("testdata/request/for/a/file/in/a/couple/of/dirs", 0755) ioutil.WriteFile("testdata/request/for/a/file/in/a/couple/of/dirs/128k", buf, 0644) b.ResetTimer() @@ -541,11 +543,13 @@ func BenchmarkRequestInSingleFile(b *testing.B) { } func TestDeviceRename(t *testing.T) { + testOs := &fatalOs{t} + hello := protocol.HelloResult{ ClientName: "syncthing", ClientVersion: "v0.9.4", } - defer os.Remove("testdata/tmpconfig.xml") + defer testOs.Remove("testdata/tmpconfig.xml") rawCfg := config.New(device1) rawCfg.Devices = []config.DeviceConfiguration{ @@ -613,6 +617,8 @@ func TestDeviceRename(t *testing.T) { } func TestClusterConfig(t *testing.T) { + testOs := &fatalOs{t} + cfg := config.New(device1) cfg.Devices = []config.DeviceConfiguration{ { @@ -654,7 +660,7 @@ func TestClusterConfig(t *testing.T) { db := db.OpenMemory() wrapper := createTmpWrapper(cfg) - defer os.Remove(wrapper.ConfigPath()) + defer testOs.Remove(wrapper.ConfigPath()) m := NewModel(wrapper, protocol.LocalDeviceID, "syncthing", "dev", db, nil) m.AddFolder(cfg.Folders[0]) m.AddFolder(cfg.Folders[1]) @@ -709,6 +715,8 @@ func TestClusterConfig(t *testing.T) { } func TestIntroducer(t *testing.T) { + testOs := &fatalOs{t} + var introducedByAnyone protocol.DeviceID // LocalDeviceID is a magic value meaning don't check introducer @@ -748,7 +756,7 @@ func TestIntroducer(t *testing.T) { }, }, }) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) m.ClusterConfig(device1, protocol.ClusterConfig{ Folders: []protocol.Folder{ { @@ -801,7 +809,7 @@ func TestIntroducer(t *testing.T) { }, }, }) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) m.ClusterConfig(device1, protocol.ClusterConfig{ Folders: []protocol.Folder{ { @@ -860,7 +868,7 @@ func TestIntroducer(t *testing.T) { }, }, }) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) m.ClusterConfig(device1, protocol.ClusterConfig{}) if _, ok := wcfg.Device(device2); ok { @@ -908,7 +916,7 @@ func TestIntroducer(t *testing.T) { }, }, }) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) m.ClusterConfig(device1, protocol.ClusterConfig{}) if _, ok := wcfg.Device(device2); !ok { @@ -955,7 +963,7 @@ func TestIntroducer(t *testing.T) { }, }, }) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) m.ClusterConfig(device1, protocol.ClusterConfig{ Folders: []protocol.Folder{ { @@ -1015,7 +1023,7 @@ func TestIntroducer(t *testing.T) { }, }, }) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) m.ClusterConfig(device1, protocol.ClusterConfig{}) if _, ok := wcfg.Device(device2); !ok { @@ -1062,7 +1070,7 @@ func TestIntroducer(t *testing.T) { }, }, }) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) m.ClusterConfig(device1, protocol.ClusterConfig{}) if _, ok := wcfg.Device(device2); !ok { @@ -1079,6 +1087,8 @@ func TestIntroducer(t *testing.T) { } func TestIssue4897(t *testing.T) { + testOs := &fatalOs{t} + wcfg, m := newState(config.Configuration{ Devices: []config.DeviceConfiguration{ { @@ -1097,7 +1107,7 @@ func TestIssue4897(t *testing.T) { }, }, }) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) cm := m.generateClusterConfig(device1) if l := len(cm.Folders); l != 1 { @@ -1106,8 +1116,10 @@ func TestIssue4897(t *testing.T) { } func TestIssue5063(t *testing.T) { + testOs := &fatalOs{t} + wcfg, m := newState(defaultAutoAcceptCfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) addAndVerify := func(wg *sync.WaitGroup) { id := srand.String(8) @@ -1119,7 +1131,7 @@ func TestIssue5063(t *testing.T) { }, }, }) - os.RemoveAll(filepath.Join("testdata", id)) + testOs.RemoveAll(id) wg.Done() if fcfg, ok := wcfg.Folder(id); !ok || !fcfg.SharedWith(device1) { t.Error("expected shared", id) @@ -1136,15 +1148,17 @@ func TestIssue5063(t *testing.T) { } func TestAutoAcceptRejected(t *testing.T) { + testOs := &fatalOs{t} + // Nothing happens if AutoAcceptFolders not set tcfg := defaultAutoAcceptCfg.Copy() for i := range tcfg.Devices { tcfg.Devices[i].AutoAcceptFolders = false } wcfg, m := newState(tcfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) id := srand.String(8) - defer os.RemoveAll(filepath.Join("testdata", id)) + defer testOs.RemoveAll(id) m.ClusterConfig(device1, protocol.ClusterConfig{ Folders: []protocol.Folder{ { @@ -1160,11 +1174,13 @@ func TestAutoAcceptRejected(t *testing.T) { } func TestAutoAcceptNewFolder(t *testing.T) { + testOs := &fatalOs{t} + // New folder wcfg, m := newState(defaultAutoAcceptCfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) id := srand.String(8) - defer os.RemoveAll(filepath.Join("testdata", id)) + defer testOs.RemoveAll(id) m.ClusterConfig(device1, protocol.ClusterConfig{ Folders: []protocol.Folder{ { @@ -1179,10 +1195,12 @@ func TestAutoAcceptNewFolder(t *testing.T) { } func TestAutoAcceptNewFolderFromTwoDevices(t *testing.T) { + testOs := &fatalOs{t} + wcfg, m := newState(defaultAutoAcceptCfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) id := srand.String(8) - defer os.RemoveAll(filepath.Join("testdata", id)) + defer testOs.RemoveAll(id) m.ClusterConfig(device1, protocol.ClusterConfig{ Folders: []protocol.Folder{ { @@ -1212,12 +1230,14 @@ func TestAutoAcceptNewFolderFromTwoDevices(t *testing.T) { } func TestAutoAcceptNewFolderFromOnlyOneDevice(t *testing.T) { + testOs := &fatalOs{t} + modifiedCfg := defaultAutoAcceptCfg.Copy() modifiedCfg.Devices[2].AutoAcceptFolders = false wcfg, m := newState(modifiedCfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) id := srand.String(8) - defer os.RemoveAll(filepath.Join("testdata", id)) + defer testOs.RemoveAll(id) m.ClusterConfig(device1, protocol.ClusterConfig{ Folders: []protocol.Folder{ { @@ -1250,6 +1270,9 @@ func TestAutoAcceptNewFolderPremutationsNoPanic(t *testing.T) { if testing.Short() { t.Skip("short tests only") } + + testOs := &fatalOs{t} + id := srand.String(8) label := srand.String(8) premutations := []protocol.Folder{ @@ -1265,12 +1288,12 @@ func TestAutoAcceptNewFolderPremutationsNoPanic(t *testing.T) { for _, dev2folder := range premutations { cfg := defaultAutoAcceptCfg.Copy() if localFolder.Label != "" { - fcfg := config.NewFolderConfiguration(protocol.LocalDeviceID, localFolder.ID, localFolder.Label, fs.FilesystemTypeBasic, filepath.Join("testdata", localFolder.ID)) + fcfg := config.NewFolderConfiguration(protocol.LocalDeviceID, localFolder.ID, localFolder.Label, fs.FilesystemTypeBasic, localFolder.ID) fcfg.Paused = localFolderPaused cfg.Folders = append(cfg.Folders, fcfg) } wcfg, m := newState(cfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) m.ClusterConfig(device1, protocol.ClusterConfig{ Folders: []protocol.Folder{dev1folder}, }) @@ -1278,8 +1301,8 @@ func TestAutoAcceptNewFolderPremutationsNoPanic(t *testing.T) { Folders: []protocol.Folder{dev2folder}, }) m.Stop() - os.RemoveAll(filepath.Join("testdata", id)) - os.RemoveAll(filepath.Join("testdata", label)) + testOs.RemoveAll(id) + testOs.RemoveAll(label) } } } @@ -1287,13 +1310,15 @@ func TestAutoAcceptNewFolderPremutationsNoPanic(t *testing.T) { } func TestAutoAcceptMultipleFolders(t *testing.T) { + testOs := &fatalOs{t} + // Multiple new folders wcfg, m := newState(defaultAutoAcceptCfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) id1 := srand.String(8) - defer os.RemoveAll(filepath.Join("testdata", id1)) + defer testOs.RemoveAll(id1) id2 := srand.String(8) - defer os.RemoveAll(filepath.Join("testdata", id2)) + defer testOs.RemoveAll(id2) m.ClusterConfig(device1, protocol.ClusterConfig{ Folders: []protocol.Folder{ { @@ -1315,21 +1340,23 @@ func TestAutoAcceptMultipleFolders(t *testing.T) { } func TestAutoAcceptExistingFolder(t *testing.T) { + testOs := &fatalOs{t} + // Existing folder id := srand.String(8) idOther := srand.String(8) // To check that path does not get changed. - defer os.RemoveAll(filepath.Join("testdata", id)) - defer os.RemoveAll(filepath.Join("testdata", idOther)) + defer testOs.RemoveAll(id) + defer testOs.RemoveAll(idOther) tcfg := defaultAutoAcceptCfg.Copy() tcfg.Folders = []config.FolderConfiguration{ { ID: id, - Path: filepath.Join("testdata", idOther), // To check that path does not get changed. + Path: idOther, // To check that path does not get changed. }, } wcfg, m := newState(tcfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) if fcfg, ok := wcfg.Folder(id); !ok || fcfg.SharedWith(device1) { t.Error("missing folder, or shared", id) } @@ -1342,27 +1369,29 @@ func TestAutoAcceptExistingFolder(t *testing.T) { }, }) - if fcfg, ok := wcfg.Folder(id); !ok || !fcfg.SharedWith(device1) || fcfg.Path != filepath.Join("testdata", idOther) { + if fcfg, ok := wcfg.Folder(id); !ok || !fcfg.SharedWith(device1) || fcfg.Path != idOther { t.Error("missing folder, or unshared, or path changed", id) } } func TestAutoAcceptNewAndExistingFolder(t *testing.T) { + testOs := &fatalOs{t} + // New and existing folder id1 := srand.String(8) - defer os.RemoveAll(filepath.Join("testdata", id1)) + defer testOs.RemoveAll(id1) id2 := srand.String(8) - defer os.RemoveAll(filepath.Join("testdata", id2)) + defer testOs.RemoveAll(id2) tcfg := defaultAutoAcceptCfg.Copy() tcfg.Folders = []config.FolderConfiguration{ { ID: id1, - Path: filepath.Join("testdata", id1), // from previous test case, to verify that path doesn't get changed. + Path: id1, // from previous test case, to verify that path doesn't get changed. }, } wcfg, m := newState(tcfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) if fcfg, ok := wcfg.Folder(id1); !ok || fcfg.SharedWith(device1) { t.Error("missing folder, or shared", id1) } @@ -1387,14 +1416,16 @@ func TestAutoAcceptNewAndExistingFolder(t *testing.T) { } func TestAutoAcceptAlreadyShared(t *testing.T) { + testOs := &fatalOs{t} + // Already shared id := srand.String(8) - defer os.RemoveAll(filepath.Join("testdata", id)) + defer testOs.RemoveAll(id) tcfg := defaultAutoAcceptCfg.Copy() tcfg.Folders = []config.FolderConfiguration{ { ID: id, - Path: filepath.Join("testdata", id), + Path: id, Devices: []config.FolderDeviceConfiguration{ { DeviceID: device1, @@ -1403,7 +1434,7 @@ func TestAutoAcceptAlreadyShared(t *testing.T) { }, } wcfg, m := newState(tcfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) if fcfg, ok := wcfg.Folder(id); !ok || !fcfg.SharedWith(device1) { t.Error("missing folder, or not shared", id) } @@ -1422,14 +1453,16 @@ func TestAutoAcceptAlreadyShared(t *testing.T) { } func TestAutoAcceptNameConflict(t *testing.T) { + testOs := &fatalOs{t} + id := srand.String(8) label := srand.String(8) - os.MkdirAll(filepath.Join("testdata", id), 0777) - os.MkdirAll(filepath.Join("testdata", label), 0777) - defer os.RemoveAll(filepath.Join("testdata", id)) - defer os.RemoveAll(filepath.Join("testdata", label)) + testOs.MkdirAll(id, 0777) + testOs.MkdirAll(label, 0777) + defer testOs.RemoveAll(id) + defer testOs.RemoveAll(label) wcfg, m := newState(defaultAutoAcceptCfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) m.ClusterConfig(device1, protocol.ClusterConfig{ Folders: []protocol.Folder{ { @@ -1444,13 +1477,15 @@ func TestAutoAcceptNameConflict(t *testing.T) { } func TestAutoAcceptPrefersLabel(t *testing.T) { + testOs := &fatalOs{t} + // Prefers label, falls back to ID. wcfg, m := newState(defaultAutoAcceptCfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) id := srand.String(8) label := srand.String(8) - defer os.RemoveAll(filepath.Join("testdata", id)) - defer os.RemoveAll(filepath.Join("testdata", label)) + defer testOs.RemoveAll(id) + defer testOs.RemoveAll(label) m.ClusterConfig(device1, protocol.ClusterConfig{ Folders: []protocol.Folder{ { @@ -1465,14 +1500,17 @@ func TestAutoAcceptPrefersLabel(t *testing.T) { } func TestAutoAcceptFallsBackToID(t *testing.T) { + testOs := &fatalOs{t} + // Prefers label, falls back to ID. wcfg, m := newState(defaultAutoAcceptCfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) id := srand.String(8) label := srand.String(8) - os.MkdirAll(filepath.Join("testdata", label), 0777) - defer os.RemoveAll(filepath.Join("testdata", label)) - defer os.RemoveAll(filepath.Join("testdata", id)) + t.Log(id, label) + testOs.MkdirAll(label, 0777) + defer testOs.RemoveAll(label) + defer testOs.RemoveAll(id) m.ClusterConfig(device1, protocol.ClusterConfig{ Folders: []protocol.Folder{ { @@ -1487,14 +1525,16 @@ func TestAutoAcceptFallsBackToID(t *testing.T) { } func TestAutoAcceptPausedWhenFolderConfigChanged(t *testing.T) { + testOs := &fatalOs{t} + // Existing folder id := srand.String(8) idOther := srand.String(8) // To check that path does not get changed. - defer os.RemoveAll(filepath.Join("testdata", id)) - defer os.RemoveAll(filepath.Join("testdata", idOther)) + defer testOs.RemoveAll(id) + defer testOs.RemoveAll(idOther) tcfg := defaultAutoAcceptCfg.Copy() - fcfg := config.NewFolderConfiguration(protocol.LocalDeviceID, id, "", fs.FilesystemTypeBasic, filepath.Join("testdata", idOther)) + fcfg := config.NewFolderConfiguration(protocol.LocalDeviceID, id, "", fs.FilesystemTypeBasic, idOther) fcfg.Paused = true // The order of devices here is wrong (cfg.clean() sorts them), which will cause the folder to restart. // Because of the restart, folder gets removed from m.deviceFolder, which means that generateClusterConfig will not panic. @@ -1504,7 +1544,7 @@ func TestAutoAcceptPausedWhenFolderConfigChanged(t *testing.T) { }) tcfg.Folders = []config.FolderConfiguration{fcfg} wcfg, m := newState(tcfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) if fcfg, ok := wcfg.Folder(id); !ok || !fcfg.SharedWith(device1) { t.Error("missing folder, or not shared", id) } @@ -1524,7 +1564,7 @@ func TestAutoAcceptPausedWhenFolderConfigChanged(t *testing.T) { if fcfg, ok := wcfg.Folder(id); !ok { t.Error("missing folder") - } else if fcfg.Path != filepath.Join("testdata", idOther) { + } else if fcfg.Path != idOther { t.Error("folder path changed") } else { for _, dev := range fcfg.DeviceIDs() { @@ -1541,14 +1581,16 @@ func TestAutoAcceptPausedWhenFolderConfigChanged(t *testing.T) { } func TestAutoAcceptPausedWhenFolderConfigNotChanged(t *testing.T) { + testOs := &fatalOs{t} + // Existing folder id := srand.String(8) idOther := srand.String(8) // To check that path does not get changed. - defer os.RemoveAll(filepath.Join("testdata", id)) - defer os.RemoveAll(filepath.Join("testdata", idOther)) + defer testOs.RemoveAll(id) + defer testOs.RemoveAll(idOther) tcfg := defaultAutoAcceptCfg.Copy() - fcfg := config.NewFolderConfiguration(protocol.LocalDeviceID, id, "", fs.FilesystemTypeBasic, filepath.Join("testdata", idOther)) + fcfg := config.NewFolderConfiguration(protocol.LocalDeviceID, id, "", fs.FilesystemTypeBasic, idOther) fcfg.Paused = true // The new folder is exactly the same as the one constructed by handleAutoAccept, which means // the folder will not be restarted (even if it's paused), yet handleAutoAccept used to add the folder @@ -1561,7 +1603,7 @@ func TestAutoAcceptPausedWhenFolderConfigNotChanged(t *testing.T) { }, fcfg.Devices...) // Need to ensure this device order to avoid folder restart. tcfg.Folders = []config.FolderConfiguration{fcfg} wcfg, m := newState(tcfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) if fcfg, ok := wcfg.Folder(id); !ok || !fcfg.SharedWith(device1) { t.Error("missing folder, or not shared", id) } @@ -1581,7 +1623,7 @@ func TestAutoAcceptPausedWhenFolderConfigNotChanged(t *testing.T) { if fcfg, ok := wcfg.Folder(id); !ok { t.Error("missing folder") - } else if fcfg.Path != filepath.Join("testdata", idOther) { + } else if fcfg.Path != idOther { t.Error("folder path changed") } else { for _, dev := range fcfg.DeviceIDs() { @@ -1658,9 +1700,11 @@ func changeIgnores(t *testing.T, m *Model, expected []string) { } func TestIgnores(t *testing.T) { + testOs := &fatalOs{t} + // Assure a clean start state - os.RemoveAll(filepath.Join("testdata", config.DefaultMarkerName)) - os.MkdirAll(filepath.Join("testdata", config.DefaultMarkerName), 0644) + testOs.RemoveAll(filepath.Join("testdata", config.DefaultMarkerName)) + testOs.MkdirAll(filepath.Join("testdata", config.DefaultMarkerName), 0644) ioutil.WriteFile("testdata/.stignore", []byte(".*\nquux\n"), 0644) db := db.OpenMemory() @@ -1719,12 +1763,16 @@ func TestIgnores(t *testing.T) { changeIgnores(t, m, expected) // Make sure no .stignore file is considered valid - os.Rename("testdata/.stignore", "testdata/.stignore.bak") + defer func() { + testOs.Rename("testdata/.stignore.bak", "testdata/.stignore") + }() + testOs.Rename("testdata/.stignore", "testdata/.stignore.bak") changeIgnores(t, m, []string{}) - os.Rename("testdata/.stignore.bak", "testdata/.stignore") } func TestROScanRecovery(t *testing.T) { + testOs := &fatalOs{t} + ldb := db.OpenMemory() set := db.NewFileSet("default", defaultFs, ldb) set.Update(protocol.LocalDeviceID, []protocol.FileInfo{ @@ -1733,7 +1781,7 @@ func TestROScanRecovery(t *testing.T) { fcfg := config.FolderConfiguration{ ID: "default", - Path: "testdata/rotestfolder", + Path: "rotestfolder", Type: config.FolderTypeSendOnly, RescanIntervalS: 1, MarkerName: config.DefaultMarkerName, @@ -1746,9 +1794,9 @@ func TestROScanRecovery(t *testing.T) { }, }, }) - defer os.Remove(cfg.ConfigPath()) + defer testOs.Remove(cfg.ConfigPath()) - os.RemoveAll(fcfg.Path) + testOs.RemoveAll(fcfg.Path) m := NewModel(cfg, protocol.LocalDeviceID, "syncthing", "dev", ldb, nil) m.AddFolder(fcfg) @@ -1779,18 +1827,14 @@ func TestROScanRecovery(t *testing.T) { return } - os.Mkdir(fcfg.Path, 0700) + testOs.Mkdir(fcfg.Path, 0700) if err := waitFor("folder marker missing"); err != nil { t.Error(err) return } - fd, err := os.Create(filepath.Join(fcfg.Path, config.DefaultMarkerName)) - if err != nil { - t.Error(err) - return - } + fd, _ := testOs.Create(filepath.Join(fcfg.Path, config.DefaultMarkerName)) fd.Close() if err := waitFor(""); err != nil { @@ -1798,14 +1842,14 @@ func TestROScanRecovery(t *testing.T) { return } - os.Remove(filepath.Join(fcfg.Path, config.DefaultMarkerName)) + testOs.Remove(filepath.Join(fcfg.Path, config.DefaultMarkerName)) if err := waitFor("folder marker missing"); err != nil { t.Error(err) return } - os.Remove(fcfg.Path) + testOs.Remove(fcfg.Path) if err := waitFor("folder path missing"); err != nil { t.Error(err) @@ -1814,6 +1858,8 @@ func TestROScanRecovery(t *testing.T) { } func TestRWScanRecovery(t *testing.T) { + testOs := &fatalOs{t} + ldb := db.OpenMemory() set := db.NewFileSet("default", defaultFs, ldb) set.Update(protocol.LocalDeviceID, []protocol.FileInfo{ @@ -1822,7 +1868,7 @@ func TestRWScanRecovery(t *testing.T) { fcfg := config.FolderConfiguration{ ID: "default", - Path: "testdata/rwtestfolder", + Path: "rwtestfolder", Type: config.FolderTypeSendReceive, RescanIntervalS: 1, MarkerName: config.DefaultMarkerName, @@ -1835,9 +1881,9 @@ func TestRWScanRecovery(t *testing.T) { }, }, }) - defer os.Remove(cfg.ConfigPath()) + defer testOs.Remove(cfg.ConfigPath()) - os.RemoveAll(fcfg.Path) + testOs.RemoveAll(fcfg.Path) m := NewModel(cfg, protocol.LocalDeviceID, "syncthing", "dev", ldb, nil) m.AddFolder(fcfg) @@ -1868,37 +1914,33 @@ func TestRWScanRecovery(t *testing.T) { return } - os.Mkdir(fcfg.Path, 0700) + testOs.Mkdir(fcfg.Path, 0700) if err := waitFor("folder marker missing"); err != nil { t.Error(err) return } - fd, err := os.Create(filepath.Join(fcfg.Path, config.DefaultMarkerName)) + fd, err := testOs.Create(filepath.Join(fcfg.Path, config.DefaultMarkerName)) if err != nil { - t.Error(err) - return + t.Fatal(err) } fd.Close() if err := waitFor(""); err != nil { - t.Error(err) - return + t.Fatal(err) } - os.Remove(filepath.Join(fcfg.Path, config.DefaultMarkerName)) + testOs.Remove(filepath.Join(fcfg.Path, config.DefaultMarkerName)) if err := waitFor("folder marker missing"); err != nil { - t.Error(err) - return + t.Fatal(err) } - os.Remove(fcfg.Path) + testOs.Remove(fcfg.Path) if err := waitFor("folder path missing"); err != nil { - t.Error(err) - return + t.Fatal(err) } } @@ -2348,16 +2390,18 @@ func benchmarkTree(b *testing.B, n1, n2 int) { } func TestIssue3028(t *testing.T) { + testOs := &fatalOs{t} + // Create two files that we'll delete, one with a name that is a prefix of the other. if err := ioutil.WriteFile("testdata/testrm", []byte("Hello"), 0644); err != nil { t.Fatal(err) } - defer os.Remove("testdata/testrm") + defer testOs.Remove("testdata/testrm") if err := ioutil.WriteFile("testdata/testrm2", []byte("Hello"), 0644); err != nil { t.Fatal(err) } - defer os.Remove("testdata/testrm2") + defer testOs.Remove("testdata/testrm2") // Create a model and default folder @@ -2379,8 +2423,8 @@ func TestIssue3028(t *testing.T) { // Delete and rescan specifically these two - os.Remove("testdata/testrm") - os.Remove("testdata/testrm2") + testOs.Remove("testdata/testrm") + testOs.Remove("testdata/testrm2") m.ScanFolderSubdirs("default", []string{"testrm", "testrm2"}) // Verify that the number of files decreased by two and the number of @@ -2403,11 +2447,13 @@ func TestIssue3028(t *testing.T) { } func TestIssue4357(t *testing.T) { + testOs := &fatalOs{t} + db := db.OpenMemory() cfg := defaultCfgWrapper.RawCopy() // Create a separate wrapper not to pollute other tests. wrapper := createTmpWrapper(config.Configuration{}) - defer os.Remove(wrapper.ConfigPath()) + defer testOs.Remove(wrapper.ConfigPath()) m := NewModel(wrapper, protocol.LocalDeviceID, "syncthing", "dev", db, nil) m.ServeBackground() defer m.Stop() @@ -2480,6 +2526,8 @@ func TestIssue4357(t *testing.T) { } func TestIssue2782(t *testing.T) { + testOs := &fatalOs{t} + // CheckHealth should accept a symlinked folder, when using tilde-expanded path. if runtime.GOOS == "windows" { @@ -2509,7 +2557,7 @@ func TestIssue2782(t *testing.T) { if err := os.Symlink("syncdir", testDir+"/synclink"); err != nil { t.Skip(err) } - defer os.RemoveAll(testDir) + defer testOs.RemoveAll(testDir) db := db.OpenMemory() m := NewModel(defaultCfgWrapper, protocol.LocalDeviceID, "syncthing", "dev", db, nil) @@ -2556,6 +2604,8 @@ func TestIndexesForUnknownDevicesDropped(t *testing.T) { } func TestSharedWithClearedOnDisconnect(t *testing.T) { + testOs := &fatalOs{t} + dbi := db.OpenMemory() fcfg := config.NewFolderConfiguration(protocol.LocalDeviceID, "default", "default", fs.FilesystemTypeBasic, "testdata") @@ -2576,7 +2626,7 @@ func TestSharedWithClearedOnDisconnect(t *testing.T) { } wcfg := createTmpWrapper(cfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) m := NewModel(wcfg, protocol.LocalDeviceID, "syncthing", "dev", dbi, nil) m.AddFolder(fcfg) @@ -2794,6 +2844,8 @@ func TestIssue3829(t *testing.T) { func TestNoRequestsFromPausedDevices(t *testing.T) { t.Skip("broken, fails randomly, #3843") + testOs := &fatalOs{t} + dbi := db.OpenMemory() fcfg := config.NewFolderConfiguration(protocol.LocalDeviceID, "default", "default", fs.FilesystemTypeBasic, "testdata") @@ -2814,7 +2866,7 @@ func TestNoRequestsFromPausedDevices(t *testing.T) { } wcfg := createTmpWrapper(cfg) - defer os.Remove(wcfg.ConfigPath()) + defer testOs.Remove(wcfg.ConfigPath()) m := NewModel(wcfg, protocol.LocalDeviceID, "syncthing", "dev", dbi, nil) m.AddFolder(fcfg) @@ -3066,6 +3118,8 @@ func TestInternalScan(t *testing.T) { } func TestCustomMarkerName(t *testing.T) { + testOs := &fatalOs{t} + ldb := db.OpenMemory() set := db.NewFileSet("default", defaultFs, ldb) set.Update(protocol.LocalDeviceID, []protocol.FileInfo{ @@ -3074,7 +3128,7 @@ func TestCustomMarkerName(t *testing.T) { fcfg := config.FolderConfiguration{ ID: "default", - Path: "testdata/rwtestfolder", + Path: "rwtestfolder", Type: config.FolderTypeSendReceive, RescanIntervalS: 1, MarkerName: "myfile", @@ -3087,10 +3141,10 @@ func TestCustomMarkerName(t *testing.T) { }, }, }) - defer os.Remove(cfg.ConfigPath()) + defer testOs.Remove(cfg.ConfigPath()) - os.RemoveAll(fcfg.Path) - defer os.RemoveAll(fcfg.Path) + testOs.RemoveAll(fcfg.Path) + defer testOs.RemoveAll(fcfg.Path) m := NewModel(cfg, protocol.LocalDeviceID, "syncthing", "dev", ldb, nil) m.AddFolder(fcfg) @@ -3117,21 +3171,15 @@ func TestCustomMarkerName(t *testing.T) { } if err := waitFor("folder path missing"); err != nil { - t.Error(err) - return + t.Fatal(err) } - os.Mkdir(fcfg.Path, 0700) - fd, err := os.Create(filepath.Join(fcfg.Path, "myfile")) - if err != nil { - t.Error(err) - return - } + testOs.Mkdir(fcfg.Path, 0700) + fd, _ := testOs.Create(filepath.Join(fcfg.Path, "myfile")) fd.Close() if err := waitFor(""); err != nil { - t.Error(err) - return + t.Fatal(err) } } @@ -3277,6 +3325,8 @@ func TestIssue4475(t *testing.T) { } func TestVersionRestore(t *testing.T) { + testOs := &fatalOs{t} + // We create a bunch of files which we restore // In each file, we write the filename as the content // We verify that the content matches at the expected filenames @@ -3285,7 +3335,7 @@ func TestVersionRestore(t *testing.T) { if err != nil { t.Fatal(err) } - defer os.RemoveAll(dir) + defer testOs.RemoveAll(dir) dbi := db.OpenMemory() @@ -3298,7 +3348,7 @@ func TestVersionRestore(t *testing.T) { Folders: []config.FolderConfiguration{fcfg}, } cfg := createTmpWrapper(rawConfig) - defer os.Remove(cfg.ConfigPath()) + defer testOs.Remove(cfg.ConfigPath()) m := NewModel(cfg, protocol.LocalDeviceID, "syncthing", "dev", dbi, nil) m.AddFolder(fcfg) @@ -3489,10 +3539,12 @@ func TestVersionRestore(t *testing.T) { } func TestPausedFolders(t *testing.T) { + testOs := &fatalOs{t} + // Create a separate wrapper not to pollute other tests. cfg := defaultCfgWrapper.RawCopy() wrapper := createTmpWrapper(cfg) - defer os.Remove(wrapper.ConfigPath()) + defer testOs.Remove(wrapper.ConfigPath()) db := db.OpenMemory() m := NewModel(wrapper, protocol.LocalDeviceID, "syncthing", "dev", db, nil) @@ -3523,17 +3575,19 @@ func TestPausedFolders(t *testing.T) { } func TestIssue4094(t *testing.T) { + testOs := &fatalOs{t} + db := db.OpenMemory() // Create a separate wrapper not to pollute other tests. wrapper := createTmpWrapper(config.Configuration{}) - defer os.Remove(wrapper.ConfigPath()) + defer testOs.Remove(wrapper.ConfigPath()) m := NewModel(wrapper, protocol.LocalDeviceID, "syncthing", "dev", db, nil) m.ServeBackground() defer m.Stop() // Force the model to wire itself and add the folders - folderPath := "testdata/nonexistent" - defer os.RemoveAll(folderPath) + folderPath := "nonexistent" + defer testOs.RemoveAll(folderPath) cfg := defaultCfgWrapper.RawCopy() fcfg := config.FolderConfiguration{ ID: "folder1", @@ -3560,17 +3614,19 @@ func TestIssue4094(t *testing.T) { } func TestIssue4903(t *testing.T) { + testOs := &fatalOs{t} + db := db.OpenMemory() // Create a separate wrapper not to pollute other tests. wrapper := createTmpWrapper(config.Configuration{}) - defer os.Remove(wrapper.ConfigPath()) + defer testOs.Remove(wrapper.ConfigPath()) m := NewModel(wrapper, protocol.LocalDeviceID, "syncthing", "dev", db, nil) m.ServeBackground() defer m.Stop() // Force the model to wire itself and add the folders - folderPath := "testdata/nonexistent" - defer os.RemoveAll(folderPath) + folderPath := "nonexistent" + defer testOs.RemoveAll(folderPath) cfg := defaultCfgWrapper.RawCopy() fcfg := config.FolderConfiguration{ ID: "folder1", @@ -3623,11 +3679,13 @@ func TestIssue5002(t *testing.T) { } func TestParentOfUnignored(t *testing.T) { + testOs := &fatalOs{t} + wcfg, m := newState(defaultCfg) defer func() { m.Stop() defaultFolderConfig.Filesystem().Remove(".stignore") - os.Remove(wcfg.ConfigPath()) + testOs.Remove(wcfg.ConfigPath()) }() m.SetIgnores("default", []string{"!quux", "*"}) @@ -3658,12 +3716,13 @@ func addFakeConn(m *Model, dev protocol.DeviceID) *fakeConnection { return fc } +// TestFolderRestartZombies reproduces issue 5233, where multiple concurrent folder +// restarts would leave more than one folder runner alive. func TestFolderRestartZombies(t *testing.T) { - // This is for issue 5233, where multiple concurrent folder restarts - // would leave more than one folder runner alive. + testOs := &fatalOs{t} wrapper := createTmpWrapper(defaultCfg.Copy()) - defer os.Remove(wrapper.ConfigPath()) + defer testOs.Remove(wrapper.ConfigPath()) folderCfg, _ := wrapper.Folder("default") folderCfg.FilesystemType = fs.FilesystemTypeFake wrapper.SetFolder(folderCfg) @@ -3758,6 +3817,8 @@ func (c *alwaysChanged) Changed() bool { } func TestRequestLimit(t *testing.T) { + testOs := &fatalOs{t} + cfg := defaultCfg.Copy() cfg.Devices = append(cfg.Devices, config.NewDeviceConfiguration(device2, "device2")) cfg.Devices[1].MaxRequestKiB = 1 @@ -3767,7 +3828,7 @@ func TestRequestLimit(t *testing.T) { } m, _, wrapper := setupModelWithConnectionManual(cfg) defer m.Stop() - defer os.Remove(wrapper.ConfigPath()) + defer testOs.Remove(wrapper.ConfigPath()) file := "tmpfile" befReq := time.Now() diff --git a/lib/model/progressemitter_test.go b/lib/model/progressemitter_test.go index 2f5ec6ac0..73947bee2 100644 --- a/lib/model/progressemitter_test.go +++ b/lib/model/progressemitter_test.go @@ -8,7 +8,6 @@ package model import ( "fmt" - "os" "path/filepath" "runtime" "testing" @@ -52,10 +51,12 @@ func expectTimeout(w *events.Subscription, t *testing.T) { } func TestProgressEmitter(t *testing.T) { + testOs := &fatalOs{t} + w := events.Default.Subscribe(events.DownloadProgress) c := createTmpWrapper(config.Configuration{}) - defer os.Remove(c.ConfigPath()) + defer testOs.Remove(c.ConfigPath()) c.SetOptions(config.OptionsConfiguration{ ProgressUpdateIntervalS: 0, }) @@ -103,8 +104,10 @@ func TestProgressEmitter(t *testing.T) { } func TestSendDownloadProgressMessages(t *testing.T) { + testOs := &fatalOs{t} + c := createTmpWrapper(config.Configuration{}) - defer os.Remove(c.ConfigPath()) + defer testOs.Remove(c.ConfigPath()) c.SetOptions(config.OptionsConfiguration{ ProgressUpdateIntervalS: 0, TempIndexMinBlocks: 10, diff --git a/lib/model/requests_test.go b/lib/model/requests_test.go index 1a48ec37f..c6d9e3d1f 100644 --- a/lib/model/requests_test.go +++ b/lib/model/requests_test.go @@ -26,14 +26,16 @@ import ( ) func TestRequestSimple(t *testing.T) { + testOs := &fatalOs{t} + // Verify that the model performs a request and creates a file based on // an incoming index update. m, fc, tmpDir, w := setupModelWithConnection() defer func() { m.Stop() - os.RemoveAll(tmpDir) - os.Remove(w.ConfigPath()) + testOs.RemoveAll(tmpDir) + testOs.Remove(w.ConfigPath()) }() // We listen for incoming index updates and trigger when we see one for @@ -63,6 +65,8 @@ func TestRequestSimple(t *testing.T) { } func TestSymlinkTraversalRead(t *testing.T) { + testOs := &fatalOs{t} + // Verify that a symlink can not be traversed for reading. if runtime.GOOS == "windows" { @@ -73,8 +77,8 @@ func TestSymlinkTraversalRead(t *testing.T) { m, fc, tmpDir, w := setupModelWithConnection() defer func() { m.Stop() - os.RemoveAll(tmpDir) - os.Remove(w.ConfigPath()) + testOs.RemoveAll(tmpDir) + testOs.Remove(w.ConfigPath()) }() // We listen for incoming index updates and trigger when we see one for @@ -105,6 +109,8 @@ func TestSymlinkTraversalRead(t *testing.T) { } func TestSymlinkTraversalWrite(t *testing.T) { + testOs := &fatalOs{t} + // Verify that a symlink can not be traversed for writing. if runtime.GOOS == "windows" { @@ -115,8 +121,8 @@ func TestSymlinkTraversalWrite(t *testing.T) { m, fc, tmpDir, w := setupModelWithConnection() defer func() { m.Stop() - os.RemoveAll(tmpDir) - os.Remove(w.ConfigPath()) + testOs.RemoveAll(tmpDir) + testOs.Remove(w.ConfigPath()) }() // We listen for incoming index updates and trigger when we see one for @@ -173,13 +179,15 @@ func TestSymlinkTraversalWrite(t *testing.T) { } func TestRequestCreateTmpSymlink(t *testing.T) { + testOs := &fatalOs{t} + // Test that an update for a temporary file is invalidated m, fc, tmpDir, w := setupModelWithConnection() defer func() { m.Stop() - os.RemoveAll(tmpDir) - os.Remove(w.ConfigPath()) + testOs.RemoveAll(tmpDir) + testOs.Remove(w.ConfigPath()) }() // We listen for incoming index updates and trigger when we see one for @@ -213,6 +221,8 @@ func TestRequestCreateTmpSymlink(t *testing.T) { } func TestRequestVersioningSymlinkAttack(t *testing.T) { + testOs := &fatalOs{t} + if runtime.GOOS == "windows" { t.Skip("no symlink support on Windows") } @@ -221,7 +231,7 @@ func TestRequestVersioningSymlinkAttack(t *testing.T) { // deleted symlink to escape tmpDir := createTmpDir() - defer os.RemoveAll(tmpDir) + defer testOs.RemoveAll(tmpDir) cfg := defaultCfgWrapper.RawCopy() cfg.Devices = append(cfg.Devices, config.NewDeviceConfiguration(device2, "device2")) @@ -234,7 +244,7 @@ func TestRequestVersioningSymlinkAttack(t *testing.T) { Type: "trashcan", } w := createTmpWrapper(cfg) - defer os.Remove(w.ConfigPath()) + defer testOs.Remove(w.ConfigPath()) db := db.OpenMemory() m := NewModel(w, device1, "syncthing", "dev", db, nil) @@ -243,7 +253,7 @@ func TestRequestVersioningSymlinkAttack(t *testing.T) { m.StartFolder("default") defer m.Stop() - defer os.RemoveAll(tmpDir) + defer testOs.RemoveAll(tmpDir) fc := addFakeConn(m, device2) fc.folder = "default" @@ -309,6 +319,8 @@ func TestPullInvalidIgnoredSR(t *testing.T) { func pullInvalidIgnored(t *testing.T, ft config.FolderType) { t.Helper() + testOs := &fatalOs{t} + tmpDir := createTmpDir() cfg := defaultCfgWrapper.RawCopy() cfg.Devices = append(cfg.Devices, config.NewDeviceConfiguration(device2, "device2")) @@ -321,8 +333,8 @@ func pullInvalidIgnored(t *testing.T, ft config.FolderType) { m, fc, w := setupModelWithConnectionManual(cfg) defer func() { m.Stop() - os.RemoveAll(tmpDir) - os.Remove(w.ConfigPath()) + testOs.RemoveAll(tmpDir) + testOs.Remove(w.ConfigPath()) }() // Reach in and update the ignore matcher to one that always does @@ -440,11 +452,13 @@ func pullInvalidIgnored(t *testing.T, ft config.FolderType) { } func TestIssue4841(t *testing.T) { + testOs := &fatalOs{t} + m, fc, tmpDir, w := setupModelWithConnection() defer func() { m.Stop() - os.RemoveAll(tmpDir) - os.Remove(w.ConfigPath()) + testOs.RemoveAll(tmpDir) + testOs.Remove(w.ConfigPath()) }() received := make(chan protocol.FileInfo) @@ -482,11 +496,13 @@ func TestIssue4841(t *testing.T) { } func TestRescanIfHaveInvalidContent(t *testing.T) { + testOs := &fatalOs{t} + m, fc, tmpDir, w := setupModelWithConnection() defer func() { m.Stop() - os.RemoveAll(tmpDir) - os.Remove(w.ConfigPath()) + testOs.RemoveAll(tmpDir) + testOs.Remove(w.ConfigPath()) }() payload := []byte("hello") @@ -551,11 +567,13 @@ func TestRescanIfHaveInvalidContent(t *testing.T) { } func TestParentDeletion(t *testing.T) { + testOs := &fatalOs{t} + m, fc, tmpDir, w := setupModelWithConnection() defer func() { m.Stop() - os.RemoveAll(tmpDir) - os.Remove(w.ConfigPath()) + testOs.RemoveAll(tmpDir) + testOs.Remove(w.ConfigPath()) }() parent := "foo" @@ -637,11 +655,13 @@ func TestRequestSymlinkWindows(t *testing.T) { t.Skip("windows specific test") } + testOs := &fatalOs{t} + m, fc, tmpDir, w := setupModelWithConnection() defer func() { m.Stop() - os.RemoveAll(tmpDir) - os.Remove(w.ConfigPath()) + testOs.RemoveAll(tmpDir) + testOs.Remove(w.ConfigPath()) }() first := make(chan struct{}) @@ -724,7 +744,7 @@ func setupModelWithConnectionManual(cfg config.Configuration) (*Model, *fakeConn } func createTmpDir() string { - tmpDir, err := ioutil.TempDir("testdata", "_request-") + tmpDir, err := ioutil.TempDir("", "_request-") if err != nil { panic("Failed to create temporary testing dir") } @@ -741,11 +761,13 @@ func equalContents(path string, contents []byte) error { } func TestRequestRemoteRenameChanged(t *testing.T) { + testOs := &fatalOs{t} + m, fc, tmpDir, w := setupModelWithConnection() defer func() { m.Stop() - os.RemoveAll(tmpDir) - os.Remove(w.ConfigPath()) + testOs.RemoveAll(tmpDir) + testOs.Remove(w.ConfigPath()) }() tfs := fs.NewFilesystem(fs.FilesystemTypeBasic, tmpDir) @@ -823,11 +845,13 @@ func TestRequestRemoteRenameChanged(t *testing.T) { } func TestRequestRemoteRenameConflict(t *testing.T) { + testOs := &fatalOs{t} + m, fc, tmpDir, w := setupModelWithConnection() defer func() { m.Stop() - os.RemoveAll(tmpDir) - os.Remove(w.ConfigPath()) + testOs.RemoveAll(tmpDir) + testOs.Remove(w.ConfigPath()) }() tfs := fs.NewFilesystem(fs.FilesystemTypeBasic, tmpDir) @@ -919,11 +943,13 @@ func TestRequestRemoteRenameConflict(t *testing.T) { } func TestRequestDeleteChanged(t *testing.T) { + testOs := &fatalOs{t} + m, fc, tmpDir, w := setupModelWithConnection() defer func() { m.Stop() - os.RemoveAll(tmpDir) - os.Remove(w.ConfigPath()) + testOs.RemoveAll(tmpDir) + testOs.Remove(w.ConfigPath()) }() tfs := fs.NewFilesystem(fs.FilesystemTypeBasic, tmpDir) @@ -967,7 +993,7 @@ func TestRequestDeleteChanged(t *testing.T) { // Check outcome if _, err := tfs.Lstat(a); err != nil { - if os.IsNotExist(err) { + if fs.IsNotExist(err) { t.Error(`Modified file "a" was removed`) } else { t.Error(`Error stating file "a":`, err) diff --git a/lib/model/sharedpullerstate_test.go b/lib/model/sharedpullerstate_test.go index ac01a659c..e4a6e38a4 100644 --- a/lib/model/sharedpullerstate_test.go +++ b/lib/model/sharedpullerstate_test.go @@ -7,7 +7,6 @@ package model import ( - "os" "testing" "github.com/syncthing/syncthing/lib/fs" @@ -16,11 +15,13 @@ import ( // Test creating temporary file inside read-only directory func TestReadOnlyDir(t *testing.T) { + testOs := &fatalOs{t} + // Create a read only directory, clean it up afterwards. - os.Mkdir("testdata/read_only_dir", 0555) + testOs.Mkdir("testdata/read_only_dir", 0555) defer func() { - os.Chmod("testdata/read_only_dir", 0755) - os.RemoveAll("testdata/read_only_dir") + testOs.Chmod("testdata/read_only_dir", 0755) + testOs.RemoveAll("testdata/read_only_dir") }() s := sharedPullerState{ diff --git a/lib/model/testos_test.go b/lib/model/testos_test.go new file mode 100644 index 000000000..3f01b68ee --- /dev/null +++ b/lib/model/testos_test.go @@ -0,0 +1,82 @@ +// Copyright (C) 2019 The Syncthing Authors. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +package model + +import ( + "os" + "time" +) + +// fatal is the required common interface between *testing.B and *testing.T +type fatal interface { + Fatal(...interface{}) +} + +type fatalOs struct { + fatal +} + +func (f *fatalOs) must(fn func() error) { + if err := fn(); err != nil { + f.Fatal(err) + } +} + +func (f *fatalOs) Chmod(name string, mode os.FileMode) error { + f.must(func() error { return os.Chmod(name, mode) }) + return nil +} + +func (f *fatalOs) Chtimes(name string, atime time.Time, mtime time.Time) error { + f.must(func() error { return os.Chtimes(name, atime, mtime) }) + return nil +} + +func (f *fatalOs) Create(name string) (*os.File, error) { + file, err := os.Create(name) + if err != nil { + f.Fatal(err) + } + return file, nil +} + +func (f *fatalOs) Mkdir(name string, perm os.FileMode) error { + f.must(func() error { return os.Mkdir(name, perm) }) + return nil +} + +func (f *fatalOs) MkdirAll(name string, perm os.FileMode) error { + f.must(func() error { return os.MkdirAll(name, perm) }) + return nil +} + +func (f *fatalOs) Remove(name string) error { + if err := os.Remove(name); err != nil && !os.IsNotExist(err) { + f.Fatal(err) + } + return nil +} + +func (f *fatalOs) RemoveAll(name string) error { + if err := os.RemoveAll(name); err != nil && !os.IsNotExist(err) { + f.Fatal(err) + } + return nil +} + +func (f *fatalOs) Rename(oldname, newname string) error { + f.must(func() error { return os.Rename(oldname, newname) }) + return nil +} + +func (f *fatalOs) Stat(name string) (os.FileInfo, error) { + info, err := os.Stat(name) + if err != nil { + f.Fatal(err) + } + return info, nil +}