diff --git a/lib/model/folder_sendrecv_test.go b/lib/model/folder_sendrecv_test.go index 4b353dfb8..ffbc47e3f 100644 --- a/lib/model/folder_sendrecv_test.go +++ b/lib/model/folder_sendrecv_test.go @@ -75,27 +75,24 @@ func setUpFile(filename string, blockNumbers []int) protocol.FileInfo { } } -func setUpModel(files ...protocol.FileInfo) *Model { - db := db.OpenMemory() - model := NewModel(defaultCfgWrapper, myID, "syncthing", "dev", db, nil) - model.AddFolder(defaultFolderConfig) - // Update index - model.updateLocalsFromScanning("default", files) - return model -} +func setupSendReceiveFolder(files ...protocol.FileInfo) (*Model, *sendReceiveFolder, string) { + w := createTmpWrapper(defaultCfg) + model := NewModel(w, myID, "syncthing", "dev", db.OpenMemory(), nil) + fcfg, tmpDir := testFolderConfigTmp() + model.AddFolder(fcfg) + + // Update index + if files != nil { + model.updateLocalsFromScanning("default", files) + } -func setUpSendReceiveFolder(model *Model) *sendReceiveFolder { f := &sendReceiveFolder{ folder: folder{ stateTracker: newStateTracker("default"), model: model, initialScanFinished: make(chan struct{}), ctx: context.TODO(), - FolderConfiguration: config.FolderConfiguration{ - FilesystemType: fs.FilesystemTypeBasic, - Path: "testdata", - PullerMaxPendingKiB: defaultPullerPendingKiB, - }, + FolderConfiguration: fcfg, }, queue: newJobQueue(), @@ -107,7 +104,7 @@ func setUpSendReceiveFolder(model *Model) *sendReceiveFolder { // Folders are never actually started, so no initial scan will be done close(f.initialScanFinished) - return f + return model, f, tmpDir } // Layout of the files: (indexes from the above array) @@ -125,8 +122,12 @@ func TestHandleFile(t *testing.T) { requiredFile := existingFile requiredFile.Blocks = blocks[1:] - m := setUpModel(existingFile) - f := setUpSendReceiveFolder(m) + m, f, tmpDir := setupSendReceiveFolder(existingFile) + defer func() { + os.Remove(m.cfg.ConfigPath()) + os.Remove(tmpDir) + }() + copyChan := make(chan copyBlocksState, 1) dbUpdateChan := make(chan dbUpdateJob, 1) @@ -167,8 +168,16 @@ func TestHandleFileWithTemp(t *testing.T) { requiredFile := existingFile requiredFile.Blocks = blocks[1:] - m := setUpModel(existingFile) - f := setUpSendReceiveFolder(m) + m, f, tmpDir := setupSendReceiveFolder(existingFile) + defer func() { + os.Remove(m.cfg.ConfigPath()) + os.Remove(tmpDir) + }() + + if _, err := prepareTmpFile(f.Filesystem()); err != nil { + t.Fatal(err) + } + copyChan := make(chan copyBlocksState, 1) dbUpdateChan := make(chan dbUpdateJob, 1) @@ -197,8 +206,6 @@ 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 @@ -206,9 +213,7 @@ func TestCopierFinder(t *testing.T) { // After dropping out blocks found locally: // Pull: 1, 5, 6, 8 - tempFile := filepath.Join("testdata", fs.TempName("file2")) - testOs.Remove(tempFile) - defer testOs.Remove(tempFile) + tempFile := fs.TempName("file2") existingBlocks := []int{0, 2, 3, 4, 0, 0, 7, 0} existingFile := setUpFile(fs.TempName("file"), existingBlocks) @@ -216,8 +221,16 @@ func TestCopierFinder(t *testing.T) { requiredFile.Blocks = blocks[1:] requiredFile.Name = "file2" - m := setUpModel(existingFile) - f := setUpSendReceiveFolder(m) + m, f, tmpDir := setupSendReceiveFolder(existingFile) + defer func() { + os.Remove(m.cfg.ConfigPath()) + os.Remove(tmpDir) + }() + + if _, err := prepareTmpFile(f.Filesystem()); err != nil { + t.Fatal(err) + } + copyChan := make(chan copyBlocksState) pullChan := make(chan pullBlockState, 4) finisherChan := make(chan *sharedPullerState, 1) @@ -259,7 +272,7 @@ func TestCopierFinder(t *testing.T) { } // Verify that the fetched blocks have actually been written to the temp file - blks, err := scanner.HashFile(context.TODO(), fs.NewFilesystem(fs.FilesystemTypeBasic, "."), tempFile, protocol.MinBlockSize, nil, false) + blks, err := scanner.HashFile(context.TODO(), f.Filesystem(), tempFile, protocol.MinBlockSize, nil, false) if err != nil { t.Log(err) } @@ -273,9 +286,15 @@ func TestCopierFinder(t *testing.T) { } func TestWeakHash(t *testing.T) { - testOs := &fatalOs{t} + // Setup the model/pull environment + model, fo, tmpDir := setupSendReceiveFolder() + defer func() { + os.Remove(model.cfg.ConfigPath()) + os.Remove(tmpDir) + }() + ffs := fo.Filesystem() - tempFile := filepath.Join("testdata", fs.TempName("weakhash")) + tempFile := fs.TempName("weakhash") var shift int64 = 10 var size int64 = 1 << 20 expectBlocks := int(size / protocol.MinBlockSize) @@ -284,18 +303,12 @@ func TestWeakHash(t *testing.T) { expectPulls++ } - cleanup := func() { - for _, path := range []string{tempFile, "testdata/weakhash"} { - testOs.Remove(path) - } + f, err := ffs.Create("weakhash") + if err != nil { + t.Fatal(err) } - - cleanup() - defer cleanup() - - 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) } @@ -337,9 +350,8 @@ func TestWeakHash(t *testing.T) { ModifiedS: info.ModTime().Unix() + 1, } - // Setup the model/pull environment - m := setUpModel(existingFile) - fo := setUpSendReceiveFolder(m) + model.updateLocalsFromScanning("default", []protocol.FileInfo{existingFile}) + copyChan := make(chan copyBlocksState) pullChan := make(chan pullBlockState, expectBlocks) finisherChan := make(chan *sharedPullerState, 1) @@ -372,7 +384,9 @@ func TestWeakHash(t *testing.T) { } finish.fd.Close() - testOs.Remove(tempFile) + if err := ffs.Remove(tempFile); err != nil { + t.Fatal(err) + } // Test 2 - using weak hash, expectPulls blocks pulled. fo.WeakHashThresholdPct = -1 @@ -405,7 +419,11 @@ func TestCopierCleanup(t *testing.T) { // Create a file file := setUpFile("test", []int{0}) - m := setUpModel(file) + m, _, tmpDir := setupSendReceiveFolder(file) + defer func() { + os.Remove(m.cfg.ConfigPath()) + os.Remove(tmpDir) + }() file.Blocks = []protocol.BlockInfo{blocks[1]} file.Version = file.Version.Update(myID.Short()) @@ -435,21 +453,17 @@ 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 testOs.Remove("testdata/" + fs.TempName("filex")) - db := db.OpenMemory() - - m := NewModel(defaultCfgWrapper, myID, "syncthing", "dev", db, nil) - m.AddFolder(defaultFolderConfig) + m, f, tmpDir := setupSendReceiveFolder() + defer func() { + os.Remove(m.cfg.ConfigPath()) + os.Remove(tmpDir) + }() // Set up our evet subscription early s := events.Default.Subscribe(events.ItemFinished) - f := setUpSendReceiveFolder(m) - // queue.Done should be called by the finisher routine f.queue.Push("filex", 0, time.Time{}) f.queue.Pop() @@ -529,20 +543,17 @@ 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 testOs.Remove("testdata/" + fs.TempName("filex")) - db := db.OpenMemory() - m := NewModel(defaultCfgWrapper, myID, "syncthing", "dev", db, nil) - m.AddFolder(defaultFolderConfig) + m, f, tmpDir := setupSendReceiveFolder() + defer func() { + os.Remove(m.cfg.ConfigPath()) + os.Remove(tmpDir) + }() // Set up our evet subscription early s := events.Default.Subscribe(events.ItemFinished) - f := setUpSendReceiveFolder(m) - // queue.Done should be called by the finisher routine f.queue.Push("filex", 0, time.Time{}) f.queue.Pop() @@ -612,26 +623,30 @@ func TestDeregisterOnFailInPull(t *testing.T) { } func TestIssue3164(t *testing.T) { - m := setUpModel(protocol.FileInfo{}) - f := setUpSendReceiveFolder(m) + m, f, tmpDir := setupSendReceiveFolder() + defer func() { + os.Remove(m.cfg.ConfigPath()) + os.Remove(tmpDir) + }() - defaultFs.RemoveAll("issue3164") - defer defaultFs.RemoveAll("issue3164") + ffs := f.Filesystem() - if err := defaultFs.MkdirAll("issue3164/oktodelete/foobar", 0777); err != nil { + ignDir := filepath.Join("issue3164", "oktodelete") + subDir := filepath.Join(ignDir, "foobar") + if err := ffs.MkdirAll(subDir, 0777); err != nil { t.Fatal(err) } - if err := ioutil.WriteFile("testdata/issue3164/oktodelete/foobar/file", []byte("Hello"), 0644); err != nil { + if err := ioutil.WriteFile(filepath.Join(tmpDir, subDir, "file"), []byte("Hello"), 0644); err != nil { t.Fatal(err) } - if err := ioutil.WriteFile("testdata/issue3164/oktodelete/file", []byte("Hello"), 0644); err != nil { + if err := ioutil.WriteFile(filepath.Join(tmpDir, ignDir, "file"), []byte("Hello"), 0644); err != nil { t.Fatal(err) } file := protocol.FileInfo{ Name: "issue3164", } - matcher := ignore.New(defaultFs) + matcher := ignore.New(ffs) if err := matcher.Parse(bytes.NewBufferString("(?d)oktodelete"), ""); err != nil { t.Fatal(err) } @@ -640,7 +655,7 @@ func TestIssue3164(t *testing.T) { f.handleDeleteDir(file, matcher, dbUpdateChan, make(chan string)) - if _, err := defaultFs.Stat("testdata/issue3164"); !fs.IsNotExist(err) { + if _, err := ffs.Stat("issue3164"); !fs.IsNotExist(err) { t.Fatal(err) } } @@ -707,8 +722,11 @@ func TestDiffEmpty(t *testing.T) { // option is true and the permissions do not match between the file on disk and // in the db. func TestDeleteIgnorePerms(t *testing.T) { - m := setUpModel() - f := setUpSendReceiveFolder(m) + m, f, tmpDir := setupSendReceiveFolder() + defer func() { + os.Remove(m.cfg.ConfigPath()) + os.Remove(tmpDir) + }() f.IgnorePerms = true ffs := f.Filesystem() @@ -717,7 +735,6 @@ func TestDeleteIgnorePerms(t *testing.T) { if err != nil { t.Error(err) } - defer ffs.Remove(name) defer file.Close() stat, err := file.Stat() @@ -761,24 +778,10 @@ func TestCopyOwner(t *testing.T) { // Set up a folder with the CopyParentOwner bit and backed by a fake // filesystem. - m := setUpModel() - f := &sendReceiveFolder{ - folder: folder{ - stateTracker: newStateTracker("default"), - model: m, - initialScanFinished: make(chan struct{}), - ctx: context.TODO(), - FolderConfiguration: config.FolderConfiguration{ - FilesystemType: fs.FilesystemTypeFake, - Path: "/TestCopyOwner", - CopyOwnershipFromParent: true, - }, - }, - - queue: newJobQueue(), - pullErrors: make(map[string]string), - pullErrorsMut: sync.NewMutex(), - } + m, f, _ := setupSendReceiveFolder() + defer os.Remove(m.cfg.ConfigPath()) + f.folder.FolderConfiguration = config.NewFolderConfiguration(m.id, f.ID, f.Label, fs.FilesystemTypeFake, "/TestCopyOwner") + f.folder.FolderConfiguration.CopyOwnershipFromParent = true f.fs = f.Filesystem() diff --git a/lib/model/model_test.go b/lib/model/model_test.go index 2156bd49f..6178b543e 100644 --- a/lib/model/model_test.go +++ b/lib/model/model_test.go @@ -11,6 +11,7 @@ import ( "context" "encoding/json" "fmt" + "io" "io/ioutil" "math/rand" "net" @@ -123,12 +124,8 @@ func TestMain(m *testing.M) { } } - tmpName := fs.TempName("file") - if err := osutil.Copy(defaultFs, "tmpfile", tmpName); err != nil { - panic(err) - } - future := time.Now().Add(time.Hour) - if err := os.Chtimes(filepath.Join("testdata", tmpName), future, future); err != nil { + tmpName, err := prepareTmpFile(defaultFs) + if err != nil { panic(err) } @@ -142,6 +139,28 @@ func TestMain(m *testing.M) { os.Exit(exitCode) } +func prepareTmpFile(to fs.Filesystem) (string, error) { + tmpName := fs.TempName("file") + in, err := defaultFs.Open("tmpfile") + if err != nil { + return "", err + } + defer in.Close() + out, err := to.Create(tmpName) + if err != nil { + return "", err + } + defer out.Close() + if _, err = io.Copy(out, in); err != nil { + return "", err + } + future := time.Now().Add(time.Hour) + if err := os.Chtimes(filepath.Join("testdata", tmpName), future, future); err != nil { + return "", err + } + return tmpName, nil +} + func createTmpWrapper(cfg config.Configuration) *config.Wrapper { tmpFile, err := ioutil.TempFile(tmpLocation, "syncthing-testConfig-") if err != nil { @@ -2879,15 +2898,13 @@ func TestIssue2571(t *testing.T) { t.Skip("Scanning symlinks isn't supported on windows") } - err := defaultFs.MkdirAll("replaceDir", 0755) - if err != nil { - t.Fatal(err) - } + w, tmpDir := tmpDefaultWrapper() defer func() { - defaultFs.RemoveAll("replaceDir") + os.RemoveAll(tmpDir) + os.Remove(w.ConfigPath()) }() - testFs := fs.NewFilesystem(fs.FilesystemTypeBasic, filepath.Join(defaultFs.URI(), "replaceDir")) + testFs := fs.NewFilesystem(fs.FilesystemTypeBasic, tmpDir) for _, dir := range []string{"toLink", "linkTarget"} { err := testFs.MkdirAll(dir, 0775) @@ -2901,9 +2918,9 @@ func TestIssue2571(t *testing.T) { fd.Close() } - m := setupModel(defaultCfgWrapper) + m := setupModel(w) - if err = testFs.RemoveAll("toLink"); err != nil { + if err := testFs.RemoveAll("toLink"); err != nil { t.Fatal(err) } @@ -2913,12 +2930,12 @@ func TestIssue2571(t *testing.T) { m.ScanFolder("default") - if dir, ok := m.CurrentFolderFile("default", filepath.Join("replaceDir", "toLink")); !ok { + if dir, ok := m.CurrentFolderFile("default", "toLink"); !ok { t.Fatalf("Dir missing in db") } else if !dir.IsSymlink() { t.Errorf("Dir wasn't changed to symlink") } - if file, ok := m.CurrentFolderFile("default", filepath.Join("replaceDir", "toLink", "a")); !ok { + if file, ok := m.CurrentFolderFile("default", filepath.Join("toLink", "a")); !ok { t.Fatalf("File missing in db") } else if !file.Deleted { t.Errorf("File below symlink has not been marked as deleted") @@ -2931,25 +2948,30 @@ func TestIssue4573(t *testing.T) { t.Skip("Can't make the dir inaccessible on windows") } - err := defaultFs.MkdirAll("inaccessible", 0755) + w, tmpDir := tmpDefaultWrapper() + defer func() { + os.RemoveAll(tmpDir) + os.Remove(w.ConfigPath()) + }() + + testFs := fs.NewFilesystem(fs.FilesystemTypeBasic, tmpDir) + + err := testFs.MkdirAll("inaccessible", 0755) if err != nil { t.Fatal(err) } - defer func() { - defaultFs.Chmod("inaccessible", 0777) - defaultFs.RemoveAll("inaccessible") - }() + defer testFs.Chmod("inaccessible", 0777) file := filepath.Join("inaccessible", "a") - fd, err := defaultFs.Create(file) + fd, err := testFs.Create(file) if err != nil { t.Fatal(err) } fd.Close() - m := setupModel(defaultCfgWrapper) + m := setupModel(w) - err = defaultFs.Chmod("inaccessible", 0000) + err = testFs.Chmod("inaccessible", 0000) if err != nil { t.Fatal(err) } @@ -2966,15 +2988,13 @@ func TestIssue4573(t *testing.T) { // TestInternalScan checks whether various fs operations are correctly represented // in the db after scanning. func TestInternalScan(t *testing.T) { - err := defaultFs.MkdirAll("internalScan", 0755) - if err != nil { - t.Fatal(err) - } + w, tmpDir := tmpDefaultWrapper() defer func() { - defaultFs.RemoveAll("internalScan") + os.RemoveAll(tmpDir) + os.Remove(w.ConfigPath()) }() - testFs := fs.NewFilesystem(fs.FilesystemTypeBasic, filepath.Join(defaultFs.URI(), "internalScan")) + testFs := fs.NewFilesystem(fs.FilesystemTypeBasic, tmpDir) testCases := map[string]func(protocol.FileInfo) bool{ "removeDir": func(f protocol.FileInfo) bool { @@ -3010,10 +3030,10 @@ func TestInternalScan(t *testing.T) { } } - m := setupModel(defaultCfgWrapper) + m := setupModel(w) for _, dir := range baseDirs { - if err = testFs.RemoveAll(dir); err != nil { + if err := testFs.RemoveAll(dir); err != nil { t.Fatal(err) } } @@ -3027,7 +3047,7 @@ func TestInternalScan(t *testing.T) { m.ScanFolder("default") for path, cond := range testCases { - if f, ok := m.CurrentFolderFile("default", filepath.Join("internalScan", path)); !ok { + if f, ok := m.CurrentFolderFile("default", path); !ok { t.Fatalf("%v missing in db", path) } else if cond(f) { t.Errorf("Incorrect db entry for %v", path) @@ -3166,31 +3186,32 @@ func TestRemoveDirWithContent(t *testing.T) { } func TestIssue4475(t *testing.T) { + m, conn, tmpDir, w := setupModelWithConnection() defer func() { - defaultFs.RemoveAll("delDir") + m.Stop() + os.RemoveAll(tmpDir) + os.Remove(w.ConfigPath()) }() - err := defaultFs.MkdirAll("delDir", 0755) - if err != nil { - t.Fatal(err) - } - - m := setupModel(defaultCfgWrapper) - defer m.Stop() + testFs := fs.NewFilesystem(fs.FilesystemTypeBasic, tmpDir) // Scenario: Dir is deleted locally and before syncing/index exchange // happens, a file is create in that dir on the remote. // This should result in the directory being recreated and added to the // db locally. - if err = defaultFs.RemoveAll("delDir"); err != nil { + err := testFs.MkdirAll("delDir", 0755) + if err != nil { t.Fatal(err) } m.ScanFolder("default") - conn := addFakeConn(m, device1) - conn.folder = "default" + if err = testFs.RemoveAll("delDir"); err != nil { + t.Fatal(err) + } + + m.ScanFolder("default") if fcfg, ok := m.cfg.Folder("default"); !ok || !fcfg.SharedWith(device1) { t.Fatal("not shared with device1") diff --git a/lib/model/requests_test.go b/lib/model/requests_test.go index 82c6097fb..183efa6e0 100644 --- a/lib/model/requests_test.go +++ b/lib/model/requests_test.go @@ -18,7 +18,6 @@ import ( "time" "github.com/syncthing/syncthing/lib/config" - "github.com/syncthing/syncthing/lib/db" "github.com/syncthing/syncthing/lib/events" "github.com/syncthing/syncthing/lib/fs" "github.com/syncthing/syncthing/lib/ignore" @@ -231,8 +230,6 @@ func TestRequestCreateTmpSymlink(t *testing.T) { } func TestRequestVersioningSymlinkAttack(t *testing.T) { - testOs := &fatalOs{t} - if runtime.GOOS == "windows" { t.Skip("no symlink support on Windows") } @@ -240,33 +237,19 @@ func TestRequestVersioningSymlinkAttack(t *testing.T) { // Sets up a folder with trashcan versioning and tries to use a // deleted symlink to escape - tmpDir := createTmpDir() - defer testOs.RemoveAll(tmpDir) + w, tmpDir := tmpDefaultWrapper() + defer func() { + os.RemoveAll(tmpDir) + os.Remove(w.ConfigPath()) + }() - cfg := defaultCfgWrapper.RawCopy() - cfg.Folders[0] = config.NewFolderConfiguration(myID, "default", "default", fs.FilesystemTypeBasic, tmpDir) - cfg.Folders[0].Devices = []config.FolderDeviceConfiguration{ - {DeviceID: myID}, - {DeviceID: device1}, - } - cfg.Folders[0].Versioning = config.VersioningConfiguration{ - Type: "trashcan", - } - w := createTmpWrapper(cfg) - defer testOs.Remove(w.ConfigPath()) + fcfg := w.FolderList()[0] + fcfg.Versioning = config.VersioningConfiguration{Type: "trashcan"} + w.SetFolder(fcfg) - db := db.OpenMemory() - m := NewModel(w, myID, "syncthing", "dev", db, nil) - m.AddFolder(cfg.Folders[0]) - m.ServeBackground() - m.StartFolder("default") + m, fc := setupModelWithConnectionFromWrapper(w) defer m.Stop() - defer testOs.RemoveAll(tmpDir) - - fc := addFakeConn(m, device1) - fc.folder = "default" - // Create a temporary directory that we will use as target to see if // we can escape to it tmpdir, err := ioutil.TempDir("", "syncthing-test") @@ -656,13 +639,11 @@ func TestRequestSymlinkWindows(t *testing.T) { t.Skip("windows specific test") } - testOs := &fatalOs{t} - m, fc, tmpDir, w := setupModelWithConnection() defer func() { m.Stop() - testOs.RemoveAll(tmpDir) - testOs.Remove(w.ConfigPath()) + os.RemoveAll(tmpDir) + os.Remove(w.ConfigPath()) }() done := make(chan struct{}) @@ -719,6 +700,13 @@ func TestRequestSymlinkWindows(t *testing.T) { } } +func tmpDefaultWrapper() (*config.Wrapper, string) { + w := createTmpWrapper(defaultCfgWrapper.RawCopy()) + fcfg, tmpDir := testFolderConfigTmp() + w.SetFolder(fcfg) + return w, tmpDir +} + func testFolderConfigTmp() (config.FolderConfiguration, string) { tmpDir := createTmpDir() return testFolderConfig(tmpDir), tmpDir @@ -732,9 +720,7 @@ func testFolderConfig(path string) config.FolderConfiguration { } func setupModelWithConnection() (*Model, *fakeConnection, string, *config.Wrapper) { - w := createTmpWrapper(defaultCfgWrapper.RawCopy()) - fcfg, tmpDir := testFolderConfigTmp() - w.SetFolder(fcfg) + w, tmpDir := tmpDefaultWrapper() m, fc := setupModelWithConnectionFromWrapper(w) return m, fc, tmpDir, w } diff --git a/lib/model/sharedpullerstate_test.go b/lib/model/sharedpullerstate_test.go index e4a6e38a4..80edd4057 100644 --- a/lib/model/sharedpullerstate_test.go +++ b/lib/model/sharedpullerstate_test.go @@ -7,6 +7,7 @@ package model import ( + "os" "testing" "github.com/syncthing/syncthing/lib/fs" @@ -15,18 +16,17 @@ 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. - testOs.Mkdir("testdata/read_only_dir", 0555) - defer func() { - testOs.Chmod("testdata/read_only_dir", 0755) - testOs.RemoveAll("testdata/read_only_dir") - }() + tmpDir := createTmpDir() + defer os.RemoveAll(tmpDir) + if err := os.Chmod(tmpDir, 0555); err != nil { + t.Fatal(err) + } + defer os.Chmod(tmpDir, 0755) s := sharedPullerState{ - fs: fs.NewFilesystem(fs.FilesystemTypeBasic, "testdata"), - tempName: "read_only_dir/.temp_name", + fs: fs.NewFilesystem(fs.FilesystemTypeBasic, tmpDir), + tempName: ".temp_name", mut: sync.NewRWMutex(), }