github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/backend/local/local_internal_test.go (about) 1 package local 2 3 import ( 4 "context" 5 "io/ioutil" 6 "os" 7 "path" 8 "path/filepath" 9 "runtime" 10 "testing" 11 "time" 12 13 "github.com/ncw/rclone/fs" 14 "github.com/ncw/rclone/fs/config/configmap" 15 "github.com/ncw/rclone/fs/hash" 16 "github.com/ncw/rclone/fstest" 17 "github.com/ncw/rclone/lib/file" 18 "github.com/ncw/rclone/lib/readers" 19 "github.com/stretchr/testify/assert" 20 "github.com/stretchr/testify/require" 21 ) 22 23 // TestMain drives the tests 24 func TestMain(m *testing.M) { 25 fstest.TestMain(m) 26 } 27 28 func TestMapper(t *testing.T) { 29 m := newMapper() 30 assert.Equal(t, m.m, map[string]string{}) 31 assert.Equal(t, "potato", m.Save("potato", "potato")) 32 assert.Equal(t, m.m, map[string]string{}) 33 assert.Equal(t, "-r'áö", m.Save("-r?'a´o¨", "-r'áö")) 34 assert.Equal(t, m.m, map[string]string{ 35 "-r'áö": "-r?'a´o¨", 36 }) 37 assert.Equal(t, "potato", m.Load("potato")) 38 assert.Equal(t, "-r?'a´o¨", m.Load("-r'áö")) 39 } 40 41 // Test copy with source file that's updating 42 func TestUpdatingCheck(t *testing.T) { 43 r := fstest.NewRun(t) 44 defer r.Finalise() 45 filePath := "sub dir/local test" 46 r.WriteFile(filePath, "content", time.Now()) 47 48 fd, err := file.Open(path.Join(r.LocalName, filePath)) 49 if err != nil { 50 t.Fatalf("failed opening file %q: %v", filePath, err) 51 } 52 defer func() { 53 require.NoError(t, fd.Close()) 54 }() 55 56 fi, err := fd.Stat() 57 require.NoError(t, err) 58 o := &Object{size: fi.Size(), modTime: fi.ModTime(), fs: &Fs{}} 59 wrappedFd := readers.NewLimitedReadCloser(fd, -1) 60 hash, err := hash.NewMultiHasherTypes(hash.Supported) 61 require.NoError(t, err) 62 in := localOpenFile{ 63 o: o, 64 in: wrappedFd, 65 hash: hash, 66 fd: fd, 67 } 68 69 buf := make([]byte, 1) 70 _, err = in.Read(buf) 71 require.NoError(t, err) 72 73 r.WriteFile(filePath, "content updated", time.Now()) 74 _, err = in.Read(buf) 75 require.Errorf(t, err, "can't copy - source file is being updated") 76 77 // turn the checking off and try again 78 in.o.fs.opt.NoCheckUpdated = true 79 80 r.WriteFile(filePath, "content updated", time.Now()) 81 _, err = in.Read(buf) 82 require.NoError(t, err) 83 84 } 85 86 func TestSymlink(t *testing.T) { 87 ctx := context.Background() 88 r := fstest.NewRun(t) 89 defer r.Finalise() 90 f := r.Flocal.(*Fs) 91 dir := f.root 92 93 // Write a file 94 modTime1 := fstest.Time("2001-02-03T04:05:10.123123123Z") 95 file1 := r.WriteFile("file.txt", "hello", modTime1) 96 97 // Write a symlink 98 modTime2 := fstest.Time("2002-02-03T04:05:10.123123123Z") 99 symlinkPath := filepath.Join(dir, "symlink.txt") 100 require.NoError(t, os.Symlink("file.txt", symlinkPath)) 101 require.NoError(t, lChtimes(symlinkPath, modTime2, modTime2)) 102 103 // Object viewed as symlink 104 file2 := fstest.NewItem("symlink.txt"+linkSuffix, "file.txt", modTime2) 105 if runtime.GOOS == "windows" { 106 file2.Size = 0 // symlinks are 0 length under Windows 107 } 108 109 // Object viewed as destination 110 file2d := fstest.NewItem("symlink.txt", "hello", modTime1) 111 112 // Check with no symlink flags 113 fstest.CheckItems(t, r.Flocal, file1) 114 fstest.CheckItems(t, r.Fremote) 115 116 // Set fs into "-L" mode 117 f.opt.FollowSymlinks = true 118 f.opt.TranslateSymlinks = false 119 f.lstat = os.Stat 120 121 fstest.CheckItems(t, r.Flocal, file1, file2d) 122 fstest.CheckItems(t, r.Fremote) 123 124 // Set fs into "-l" mode 125 f.opt.FollowSymlinks = false 126 f.opt.TranslateSymlinks = true 127 f.lstat = os.Lstat 128 129 fstest.CheckListingWithPrecision(t, r.Flocal, []fstest.Item{file1, file2}, nil, fs.ModTimeNotSupported) 130 if haveLChtimes { 131 fstest.CheckItems(t, r.Flocal, file1, file2) 132 } 133 134 // Create a symlink 135 modTime3 := fstest.Time("2002-03-03T04:05:10.123123123Z") 136 file3 := r.WriteObjectTo(ctx, r.Flocal, "symlink2.txt"+linkSuffix, "file.txt", modTime3, false) 137 if runtime.GOOS == "windows" { 138 file3.Size = 0 // symlinks are 0 length under Windows 139 } 140 fstest.CheckListingWithPrecision(t, r.Flocal, []fstest.Item{file1, file2, file3}, nil, fs.ModTimeNotSupported) 141 if haveLChtimes { 142 fstest.CheckItems(t, r.Flocal, file1, file2, file3) 143 } 144 145 // Check it got the correct contents 146 symlinkPath = filepath.Join(dir, "symlink2.txt") 147 fi, err := os.Lstat(symlinkPath) 148 require.NoError(t, err) 149 assert.False(t, fi.Mode().IsRegular()) 150 linkText, err := os.Readlink(symlinkPath) 151 require.NoError(t, err) 152 assert.Equal(t, "file.txt", linkText) 153 154 // Check that NewObject gets the correct object 155 o, err := r.Flocal.NewObject(ctx, "symlink2.txt"+linkSuffix) 156 require.NoError(t, err) 157 assert.Equal(t, "symlink2.txt"+linkSuffix, o.Remote()) 158 if runtime.GOOS != "windows" { 159 assert.Equal(t, int64(8), o.Size()) 160 } 161 162 // Check that NewObject doesn't see the non suffixed version 163 _, err = r.Flocal.NewObject(ctx, "symlink2.txt") 164 require.Equal(t, fs.ErrorObjectNotFound, err) 165 166 // Check reading the object 167 in, err := o.Open(ctx) 168 require.NoError(t, err) 169 contents, err := ioutil.ReadAll(in) 170 require.NoError(t, err) 171 require.Equal(t, "file.txt", string(contents)) 172 require.NoError(t, in.Close()) 173 174 // Check reading the object with range 175 in, err = o.Open(ctx, &fs.RangeOption{Start: 2, End: 5}) 176 require.NoError(t, err) 177 contents, err = ioutil.ReadAll(in) 178 require.NoError(t, err) 179 require.Equal(t, "file.txt"[2:5+1], string(contents)) 180 require.NoError(t, in.Close()) 181 } 182 183 func TestSymlinkError(t *testing.T) { 184 m := configmap.Simple{ 185 "links": "true", 186 "copy_links": "true", 187 } 188 _, err := NewFs("local", "/", m) 189 assert.Equal(t, errLinksAndCopyLinks, err) 190 }